Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см. версию этой статьи для .NET 9.
Важно!
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В этой статье объясняется, как управлять Blazor маршрутизацией запросов приложений и как использовать NavLink компонент для создания ссылок навигации.
Важно!
Примеры кода в этой статье показывают вызовы методов на Navigation, который является инъецированным NavigationManager в классах и компонентах.
Статическая и интерактивная маршрутизация
Этот раздел относится к Blazor Web Apps.
Если предварительная отрисовка включена, Blazor маршрутизатор (Router компонент) <Router>Routes.razor выполняет статическую маршрутизацию к компонентам во время статического рендеринга на стороне сервера (статическое SSR). Этот тип маршрутизации называется статической маршрутизацией.
Когда компоненту назначен интерактивный режим отрисовки Routes, маршрутизатор Blazor становится интерактивным после выполнения статического SSR и статической маршрутизации на сервере. Этот тип маршрутизации называется интерактивной маршрутизацией.
Статические маршрутизаторы используют маршрутизацию конечных точек и путь HTTP-запроса для определения компонента для отрисовки. Когда маршрутизатор становится интерактивным, он использует URL-адрес документа (URL-адрес в адресной строке браузера) для определения компонента для отрисовки. Это означает, что интерактивный маршрутизатор может динамически изменять, какой компонент отображается, если URL-адрес документа динамически изменяется на другой допустимый внутренний URL-адрес, и он может сделать это без выполнения HTTP-запроса для получения нового содержимого страницы.
Интерактивная маршрутизация также предотвращает предварительное отображение, так как новое содержимое страницы не запрашивается с сервера с обычным запросом страницы. Дополнительные сведения см. в разделе Компоненты ASP.NET Core с предварительной отрисовкой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>
Router не взаимодействует со строковыми значениями запроса. Сведения о работе со строками запроса см. в разделе "Строки запроса".
В качестве альтернативы указанию шаблона маршрута как строкового литерала с директивой @page, шаблоны маршрутов на основе констант могут быть указаны с директивой @attribute.
В следующем примере директива @page в компоненте заменяется на директиву @attribute, а шаблон маршрута на основе констант в Constants.CounterRoute в приложении устанавливается в значение "/counter":
В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.
Фокусировка элемента при навигации
Компонент FocusOnNavigate задает фокус пользовательского интерфейса элементу на основе селектора CSS после перехода с одной страницы на другую.
Когда компонент Router переходит на новую страницу, компонент FocusOnNavigate устанавливает фокус на заголовок верхнего уровня страницы (<h1>). Это распространенная стратегия для обеспечения объявления навигации по страницам при использовании пользователем средства чтения с экрана.
Предоставление пользовательского содержимого, когда содержимое не найдено
Компонент Router позволяет приложению указать пользовательское содержимое, если содержимое для запрошенного маршрута не найдено.
Задайте настраиваемое содержимое для Router параметра компонента NotFound :
Произвольные элементы поддерживаются в качестве содержимого NotFound параметра, например других интерактивных компонентов. Сведения о применении макета по умолчанию к содержимому NotFound см. в статье Макеты Blazor в ASP.NET Core.
Важно!
Blazor Web Appне используют параметр NotFound (<NotFound>...</NotFound> разметку), но параметр поддерживается† для обратной совместимости, чтобы избежать разрушающих изменений в фреймворке. Конвейер промежуточного программного обеспечения ASP.NET Core обрабатывает запросы на сервере. Используйте методы на стороне сервера для обработки плохих запросов.
†Поддержка в этом контексте означает, что помещение разметки <NotFound>...</NotFound> не приводит к исключению, но и использование разметки не приносит результата.
Используйте параметр Router компонента AdditionalAssemblies и создатель соглашений для конечных точек AddAdditionalAssemblies для обнаружения маршрутизируемых компонентов в дополнительных сборках. В следующих подразделах объясняется, когда и как использовать каждый API.
Статическая маршрутизация
Чтобы обнаружить маршрутизируемые компоненты из дополнительных сборок для статической серверной отрисовки (SSR), даже если маршрутизатор затем становится интерактивным для интерактивной отрисовки, сборки должны быть предоставлены платформе Blazor. Вызовите метод AddAdditionalAssemblies с дополнительными сборками, связанными с MapRazorComponents в файле Program проекта сервера.
Пример ниже включает маршрутизируемые компоненты в сборке проекта BlazorSample.Client с использованием файла проекта _Imports.razor.
Интерактивный режим отрисовки можно назначить компоненту Routes (Routes.razor), который делает маршрутизатор Blazor становящимся интерактивным после выполнения статического SSR и статической маршрутизации на сервере. Например, <Routes @rendermode="InteractiveServer" /> назначает интерактивную отрисовку на стороне сервера (Interactive SSR) для компонента Routes. Компонент Router наследует интерактивную серверную отрисовку (интерактивное SSR) от компонента Routes. Маршрутизатор становится интерактивным после статической маршрутизации на сервере.
Внутренняя навигация для интерактивной маршрутизации не включает запрос нового содержимого страницы с сервера. Поэтому предварительное отображение не выполняется для внутренних запросов страниц. Дополнительные сведения см. в разделе Компоненты ASP.NET Core с предварительной отрисовкойRazor.
Если компонент Routes определен в серверном проекте, то параметр AdditionalAssemblies компонента Router должен включать сборку проекта .Client. Это позволяет маршрутизатору работать правильно при интерактивном отображении.
В следующем примере компонент Routes находится в серверном проекте, а файл _Imports.razor проекта BlazorSample.Client указывает сборку, в которой следует искать маршрутизируемые компоненты.
Кроме этого, в проекте .Client существуют только маршрутизируемые компоненты с глобальным Interactive WebAssembly или Auto rendering, а компонент Routes определен в проекте .Client, а не в серверном проекте. В этом случае нет внешних сборок с маршрутизируемыми компонентами, поэтому не нужно указывать значение для AdditionalAssemblies.
Этот раздел относится к приложениям Blazor Server.
Используйте параметр Router компонента AdditionalAssemblies и создатель соглашений для конечных точек AddAdditionalAssemblies для обнаружения маршрутизируемых компонентов в дополнительных сборках.
В следующем примере Component1 — это маршрутизируемый компонент, определенный в указанной библиотеке классов компонентов с именемComponentLibrary.
Дополнительные сборки проверяются в дополнение к сборке, указанной в 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; }
}
Примечание
Ограничения маршрута не работают со значениями строки запроса. Сведения о работе со строками запроса см. в разделе "Строки запроса".
Доступны ограничения маршрутов, приведенные в следующей таблице. Сведения об ограничениях маршрута, соответствующих инвариантной культуре, см. в предупреждении под таблицей для получения дополнительной информации.
Ограничения маршрута, которые проверяют 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), что нарушает стили приложения.
Чтобы ограничить параметр маршрута записью путей, отличных от файлов, используйте :nonfile ограничение в шаблоне маршрута:
@page "/{optional:nonfile?}"
Маршрутизация URL-адресов, содержащих точки
Шаблон маршрута на стороне сервера по умолчанию предполагает, что если последний сегмент URL-адреса запроса содержит точку (.), то запрашивается файл. Например, относительный URL-адрес /example/some.thing интерпретируется маршрутизатором как запрос файла с именем some.thing. Без дополнительной настройки приложение возвращает ответ 404 — не найден, если some.thing предназначен для маршрутизации на компонент с @page директивой и some.thing является значением параметра маршрута. Чтобы использовать маршрут с одним параметром или несколькими, содержащими точку, в приложении необходимо настроить маршрут с помощью пользовательского шаблона.
Рассмотрим приведенный ниже компонент Example, который может получать параметр маршрута из последнего сегмента URL-адреса.
Чтобы разрешить Server приложению хостингового Blazor WebAssemblyрешения маршрутизировать запрос с точкой в param параметре маршрута, добавьте резервный шаблон маршрута файла с опциональным параметром в Program файле:
Чтобы настроить приложение Blazor Server для маршрутизации запроса, содержащего точку, в параметре маршрута param, добавьте в файл Program шаблон резервного маршрута страницы с необязательным параметром:
Чтобы разрешить приложению Server размещенного решения Blazor WebAssemblyмаршрутизировать запрос с точкой в параметре маршрута param, добавьте шаблон маршрута резервного файла с необязательным параметром в Startup.Configure.
Чтобы настроить приложение Blazor Server для маршрутизации запроса с точкой в параметре маршрута param, добавьте шаблон резервного маршрута страницы с дополнительным параметром в Startup.Configure.
В компонентах поддерживаются 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; }
}
Для 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 предоставляет события и методы, приведенные в следующей таблице.
Получает базовый URI (с завершающим слэшем), который можно присоединить к относительным путям URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Получает базовый URI (с завершающим слэшем), который можно присоединить к относительным путям URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Получает базовый URI (с завершающим слэшем), который можно присоединить к относительным путям URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Получает базовый URI (с завершающим слэшем), который можно присоединить к относительным путям URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
Возвращает URI, созданный путем обновления NavigationManager.Uri с добавлением, обновлением или удалением одного параметра. Дополнительные сведения см. в разделе Строки запросов.
Получает базовый URI (с завершающим слэшем), который можно присоединить к относительным путям URI для получения абсолютного URI. Как правило, BaseUri соответствует атрибуту href элемента <base> документа (расположение содержимого <head>).
В ASP.NET Core 10.0 (предварительная версия 4) ответы «Not Found» доступны только для статического SSR и глобальной интерактивной визуализации. Поддержка рендеринга на уровне страницы или компонента запланирована на релиз Preview 5 в июне 2025 года.
NavigationManagerNotFound предоставляет метод для обработки сценариев, когда запрошенный ресурс не найден во время статического рендеринга на стороне сервера (SSR) или глобального интерактивного рендеринга:
Статический SSR: вызов NotFound устанавливает код состояния HTTP на 404.
Потоковая отрисовка: выбрасывает исключение, если запуск ответа уже начался.
Интерактивная отрисовка: сигнализирует Blazor маршрутизатору (Router компоненту) для отрисовки не найденного содержимого.
Когда компонент отображается статически (статический SSR) и NavigationManager.NotFound вызывается, код состояния 404 устанавливается в ответе:
Укажите содержимое "не найдено" в свойстве компонента RouterNotFound (<NotFound>...</NotFound> разметка или путем задания параметра NotFound в качестве фрагмента отрисовки в коде C#).
В следующем примере используется страница "Не найдено" (NotFoundPage компонент) для отображения содержимого "Не найдено".
NotFoundPage.razor:
<h1>Not Found</h1>
<p>Sorry! Nothing to show.</p>
Укажите компонент NotFoundPage для компонента Router в Routes.razor. Возможно, потребуется указать пространство имен компонента с директивой @using в верхней части Routes.razor файла или в _Imports.razor файле.
Когда компонент отрисовывается с помощью глобального интерактивного режима отрисовки, вызов NotFound подаёт сигнал маршрутизатору Blazor для отрисовки содержимого "Не найдено" — компонента NotFoundPage.
Событие OnNotFound можно использовать для уведомлений при вызове NotFound. Событие запускается только когда вызывается NotFound, а не для любого ответа с кодом 404. Например, установка HttpContextAccessor.HttpContext.Response.StatusCode в 404 не вызывает NotFound/OnNotFound.
В следующем примере для компонентов, которые используют интерактивную серверную отрисовку (Interactive SSR), настраиваемое содержимое отображается в зависимости от того, где вызывается OnNotFound. Если событие активируется следующим Movie компонентом, если фильм не найден при инициализации компонента, настраиваемое сообщение указывает, что запрошенный фильм не найден. Если событие активируется User компонентом, то другое сообщение указывает, что пользователь не найден.
Следующая NotFoundContext служба управляет контекстом и сообщением, если содержимое не найдено компонентами.
NotFoundContext.cs:
public class NotFoundContext
{
public string Heading { get; private set; } = "Not Found";
public string Message { get; private set; } =
"Sorry, the page that you requested couldn't be found.";
public void UpdateContext(string heading, string message)
{
Heading = heading;
Message = message;
}
}
Служба регистрируется в серверном Program файле:
builder.Services.AddScoped<NotFoundContext>();
Компонент Routes (Routes.razor):
Внедряет NotFoundContext службу.
Отображает заголовок (Heading) и сообщение (Message), когда OnNotFound вызывается вызовом NotFound.
В OnInitializedAsync, HandleNotFound является обработчиком, назначенным для события OnNotFound.
HandleNotFound вызывает NotFoundContext.UpdateContext для задания заголовка и сообщения для содержимого "Not Found", которое отображается компонентом Router в компоненте Routes (Routes.razor).
Компоненты обычно используют идентификатор из параметра маршрута для получения фильма или пользователя из хранилища данных, например базы данных. В следующих примерах объект не возвращается (null) для имитации того, что происходит, когда сущность не найдена.
Если сущность не возвращается в OnInitializedAsync, NavigationManager.NotFound вызывается, который, в свою очередь, активирует событие OnNotFound и обработчик событий HandleNotFound. Не найденное содержимое отображается маршрутизатором.
Метод HandleNotFound отсоединяется при освобождении компонентов в IDisposable.Dispose.
Компонент Movie (Movie.razor):
@page "/movie/{Id:int}"
@implements IDisposable
@inject NavigationManager NavigationManager
@inject NotFoundContext NotFoundContext
<div>
No matter what ID is used, no matching movie is returned
from the call to GetMovie().
</div>
@code {
[Parameter]
public int Id { get; set; }
protected override async Task OnInitializedAsync()
{
NavigationManager.OnNotFound += HandleNotFound;
var movie = await GetMovie(Id);
if (movie == null)
{
NavigationManager.NotFound();
}
}
private void HandleNotFound(object? sender, NotFoundEventArgs e)
{
NotFoundContext.UpdateContext("Movie Not Found",
"Sorry! The requested movie wasn't found.");
}
private async Task<MovieItem[]?> GetMovie(int id)
{
// Simulate no movie with matching id found
return await Task.FromResult<MovieItem[]?>(null);
}
void IDisposable.Dispose()
{
NavigationManager.OnNotFound -= HandleNotFound;
}
public class MovieItem
{
public int Id { get; set; }
public string? Title { get; set; }
}
}
Компонент User (User.razor):
@page "/user/{Id:int}"
@implements IDisposable
@inject NavigationManager NavigationManager
@inject NotFoundContext NotFoundContext
<div>
No matter what ID is used, no matching user is returned
from the call to GetUser().
</div>
@code {
[Parameter]
public int Id { get; set; }
protected override async Task OnInitializedAsync()
{
NavigationManager.OnNotFound += HandleNotFound;
var user = await GetUser(Id);
if (user == null)
{
NavigationManager.NotFound();
}
}
private void HandleNotFound(object? sender, NotFoundEventArgs e)
{
NotFoundContext.UpdateContext("User Not Found",
"Sorry! The requested user wasn't found.");
}
private async Task<UserItem[]?> GetUser(int id)
{
// Simulate no user with matching id found
return await Task.FromResult<UserItem[]?>(null);
}
void IDisposable.Dispose()
{
NavigationManager.OnNotFound -= HandleNotFound;
}
public class UserItem
{
public int Id { get; set; }
public string? Name { get; set; }
}
}
Чтобы обратиться к предыдущим компонентам в локальной демонстрации с помощью тестового приложения, создайте записи в компоненте NavMenu (NavMenu.razor), чтобы получить доступ к компонентам Movie и User. Идентификаторы сущностей, передаваемые в качестве параметров маршрута, в следующем примере являются фиктивными значениями, которые не оказывают эффекта, так как они фактически не используются компонентами, имитирующими отсутствие фильма или пользователя.
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, обычно вызываются. В некоторых случаях обработчики изменения местоположения не могут перехватывать расширенную навигацию. Например, пользователь может переключиться на другую страницу перед тем, как интерактивная среда выполнения станет доступной. Поэтому важно, чтобы логика приложения не зависела от вызова обработчика изменения расположения, так как не гарантируется выполнение обработчика.
Если forceLoad — это false, как и установлено по умолчанию:
Также доступна расширенная навигация по текущему 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>
Улучшенная обработка форм не является иерархической и не будет передаваться в дочерние формы:
❌Неподдерживается: нельзя задать расширенную навигацию на элементе-предке формы, чтобы включить ее для формы.
Расширенные записи форм работают только с Blazor конечными точками. Публикация расширенной формы в непредназначенную Blazor точку приводит к ошибке.
Чтобы отключить расширенную навигацию, выполните приведенные действия.
Удалите параметр EditForm из элемента формы (или задайте для него значение Enhance: false).
Для HTML <form>удалите data-enhance атрибут из элемента формы (или задайте для него falseзначение : data-enhance="false").
BlazorУлучшенная навигация и обработка форм могут отменить динамические изменения в DOM, если обновленное содержимое не является частью рендеринга сервера. Чтобы сохранить содержимое элемента, используйте data-permanent атрибут.
В следующем примере содержимое <div> элемента динамически обновляется скриптом при загрузке страницы:
<div data-permanent>
...
</div>
После запуска Blazor на клиенте можно использовать событие enhancedload для отслеживания расширенных обновлений страниц. Это позволяет повторно применять изменения к DOM, которые, возможно, были отменены расширенным обновлением страницы.
ForceLoad: Обойти маршрутизацию на стороне клиента и принудительно загрузить новую страницу с сервера, независимо от того, обрабатывается ли URI маршрутизатором на стороне клиента. Значение по умолчанию — false.
ReplaceHistoryEntry: замените текущую запись в стеке истории. Если false, добавьте новую запись в стек истории. Значение по умолчанию — false.
HistoryEntryState: возвращает или задает состояние, которое будет добавлено к записи журнала.
Navigation.NavigateTo("/path", new NavigationOptions
{
HistoryEntryState = "Navigation state"
});
Используйте атрибут [SupplyParameterFromQuery] с атрибутом [Parameter], чтобы указать, что параметр компонента маршрутизируемого поступает из строки запроса.
Примечание
Параметры компонента могут принимать значения параметров запроса только в маршрутизируемых компонентах с директивой @page.
Только маршрутизируемые компоненты напрямую получают параметры запроса, чтобы избежать переключения потока сведений сверху вниз и очистить порядок обработки параметров, как платформы, так и приложения. Эта конструкция позволяет избежать тонких ошибок в коде приложения, написанном при условии определенного порядка обработки параметров. Вы можете задать настраиваемые каскадные параметры или напрямую назначить их обычным параметрам компонента, чтобы передать значения параметров запроса в нераутируемые компоненты.
Параметры компонента, предоставляемые из строки запроса, поддерживают следующие типы:
Варианты предыдущих типов, допускающие значение NULL.
Массивы предыдущих типов, допускающие или не допускающие значение NULL.
Корректное инвариантное форматирование относительно культуры применяется для данного типа (CultureInfo.InvariantCulture).
Укажите свойство [SupplyParameterFromQuery] атрибута Name, чтобы использовать имя параметра запроса, отличное от имени параметра компонента. В следующем примере в C# именем параметра компонента является {COMPONENT PARAMETER NAME}. Для заполнителя {QUERY PARAMETER NAME} указано другое имя параметра запроса:
В отличие от свойств параметров компонента ([Parameter]), свойства [SupplyParameterFromQuery] можно пометить private, так же, как и public.
Как и свойства параметра компонента ([Parameter]), [SupplyParameterFromQuery] свойства в .NET 6/7 всегда являются public свойствами. В .NET 8 и более поздних версиях свойства [SupplyParameterFromQuery] можно пометить как public или private.
В следующем примере с 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.
Примечание
Параметры строки запроса в следующем маршрутизируемом компоненте страницы также работают в немаршрутизируемом компоненте без @page директивы (например, для общего Search.razor компонента, Search используемого в других компонентах).
Заполнитель {NAME} указывает имя параметра запроса. Заполнитель {VALUE} указывает значение в качестве поддерживаемого типа. Поддерживаемые типы перечислены далее в этом разделе.
Строка возвращается, равная текущему URL-адресу с одним параметром:
Добавляется, если имя параметра запроса не существует в текущем URL-адресе.
Изменено на значение, указываемое в том случае, если параметр запроса существует в текущем URL-адресе.
Удаляется, если тип предоставленного значения является нулевой, а значение равно c0.
Корректное инвариантное форматирование относительно культуры применяется для данного типа (CultureInfo.InvariantCulture).
Имя и значение параметра запроса кодируются в виде URL-адреса.
Все значения с соответствующим именем параметра запроса заменяются при наличии нескольких экземпляров типа.
Вызовите GetUriWithQueryParameters для создания URI, созданного из Uri, с добавлением, обновлением или удалением нескольких параметров. Для каждого значения платформа использует value?.GetType() для определения времени выполнения запроса и выбирает правильный инвариантный формат для культуры. Платформа выдает ошибку для неподдерживаемых типов.
Заполнитель {PARAMETERS} — это IReadOnlyDictionary<string, object>.
Передайте строку URI в GetUriWithQueryParameters, чтобы создать новый URI из предоставленного URI с несколькими добавленными, обновленными или удаленными параметрами. Для каждого значения платформа использует value?.GetType() для определения времени выполнения запроса и выбирает правильный инвариантный формат для культуры. Платформа выдает ошибку для неподдерживаемых типов. Поддерживаемые типы перечислены далее в этом разделе.
Заполнитель {URI} — это URI с параметрами запроса или без них.
Заполнитель {PARAMETERS} — это IReadOnlyDictionary<string, object>.
Поддерживаемые типы идентичны поддерживаемым типам для ограничений маршрута:
bool
DateOnly
DateTime
decimal
double
float
Guid
int
long
string
TimeOnly
К поддерживаемым типам относятся:
Варианты предыдущих типов, допускающие значение NULL.
Массивы предыдущих типов, допускающие или не допускающие значение NULL.
Предупреждение
С помощью сжатия, который включен по умолчанию, избегайте создания безопасных (прошедших проверку подлинности или авторизованных) интерактивных компонентов на стороне сервера, отрисовывающих данные из ненадежных источников. Ненадежные источники включают параметры маршрута, строки запроса, данные из JS взаимодействия и любой другой источник данных, который может контролироваться сторонним пользователем (например, базы данных, внешние службы). Для получения дополнительной информации см. руководство по ASP.NET Core и руководство по снижению угроз для интерактивного серверного рендеринга в ASP.NET Core.
Замена значения параметра запроса, если параметр существует
Хэшированная маршрутизация к именованным элементам
Перейдите к именованному элементу с использованием следующих подходов с хэш-ссылкой на элемент #. Маршруты к элементам в компоненте и маршруты к элементам во внешних компонентах используют корневой относительный путь. Начальная косая черта (/) является необязательной.
Примеры для каждого подхода демонстрируют навигацию к элементу с id и targetElement в компоненте Counter.
В следующем примере показано использование хэш-маршрутизации для перехода к именованным заголовкам H2 внутри компонента и ко внешним компонентам.
В компонентах Home (Home.razor) и Counter (Counter.razor) поместите следующую разметку в нижней части существующей разметки компонента, чтобы использовать их в качестве целей навигации.
<div> создает искусственное вертикальное пространство для демонстрации поведения прокрутки браузера.
Добавьте следующий 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 что переход страницы происходит.
Объект NavigationContext, переданный в обратный вызов OnNavigateAsync, содержит CancellationToken, который задается при возникновении нового события навигации. Обратный вызов OnNavigateAsync должен вызываться, если этот токен отмены установлен так, чтобы не выполнять обратный вызов OnNavigateAsync для устаревшей навигации.
Если пользователь переходит на конечную точку, а затем сразу переходит к новой конечной точке, приложение не должно продолжать выполнение обратного вызова OnNavigateAsync к первой конечной точке.
В следующем примере :
Токен отмены передается в функцию, вызываемую через PostAsJsonAsync, которая может отменить запрос POST, если пользователь покидает данную конечную точку /about.
Токен отмены задается во время операции предварительной выборки продукта, если пользователь покидает конечную точку /store.
Если не выбрасывать исключение при отмене токена отмены в NavigationContext, это может привести к непредсказуемому поведению, например, к рендерингу компонента из предыдущей навигации.
Управление и предотвращение изменений местоположения
HistoryEntryState: возвращает состояние, связанное с записью в целевой истории.
IsNavigationIntercepted: возвращает значение, указывающее, была ли навигация перехвачена из ссылки.
CancellationToken: возвращает значение CancellationToken, определяющее, была ли отменена навигация, например, чтобы определить, активировал ли пользователь другую навигацию.
PreventNavigation: вызывается, чтобы предотвратить продолжение навигации.
Компонент может зарегистрировать несколько обработчиков изменения местоположения в методе жизненного цикла. Навигация вызывает все обработчики изменения расположения, зарегистрированные во всем приложении (между несколькими компонентами), и любая внутренняя навигация выполняет их одновременно. В дополнение к NavigateTo обработчики вызываются в следующих случаях:
При нажатии на внутренние ссылки, которые указывают на URL-адреса в базовом пути приложения.
При навигации с помощью кнопок "Вперед" и "Назад" в браузере.
Обработчики исполняются исключительно для навигации внутри приложения. Если пользователь нажимает на ссылку, которая ведет на другой сайт, или вручную вводит в адресную строку адрес другого сайта, обработчики изменения расположения не выполняются.
Поскольку внутренняя навигация может быть отменена асинхронно, могут произойти несколько перекрывающихся вызовов зарегистрированных обработчиков. Например, несколько вызовов обработчика могут возникать, когда пользователь быстро нажимает кнопку "Назад" на странице или когда пользователь выбирает несколько ссылок перед выполнением навигации. Ниже приведена сводка по логике асинхронной навигации:
Если регистрируются какие-либо обработчики изменения местоположения, вся навигация изначально отменяется, а затем воспроизводится, если навигация не отменена.
Если выполняются перекрывающиеся запросы навигации, последний запрос всегда отменяет предыдущие запросы, что означает следующее:
Приложение может рассматривать несколько нажатий кнопки "Назад" и "Вперед" как одно.
Если пользователь выбирает несколько ссылок до завершения процесса навигации, последняя выбранная ссылка определяет навигацию.
Ссылки в документации на справочные материалы по .NET обычно загружают основную ветвь репозитория, которая представляет собой текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного выпуска, используйте выпадающий список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Компонент NavigationLock перехватывает события навигации до тех пор, пока он отображается, фактически "блокирует" любую заданную навигацию до тех пор, пока не будет принято решение о продолжении или отмене. Используйте NavigationLock при перехвате навигации в течение времени существования компонента.
ConfirmExternalNavigation задает диалоговое окно браузера, чтобы предложить пользователю подтвердить или отменить внешнюю навигацию. Значение по умолчанию — false. Для отображения диалогового окна подтверждения требуется начальное взаимодействие пользователя со страницей перед запуском внешней навигации по URL-адресу в адресной строке браузера. Дополнительные сведения о требовании взаимодействия см. в разделе "Окно: beforeunload событие".
Используйте при создании ссылок навигации компонент NavLink вместо HTML-элементов гиперссылок (<a>). Компонент NavLink ведет себя как элемент <a>, за исключением того, что он переключает класс CSS active в зависимости от того, соответствует ли его href текущему URL-адресу. Класс active помогает пользователю понять, какая страница является активной страницей среди отображаемых ссылок навигации. При необходимости назначьте имя класса CSS свойству NavLink.ActiveClass, чтобы применить пользовательский класс CSS к отображаемой ссылке, если текущий маршрут совпадает с href.
Существует два параметра NavLinkMatch, которые можно назначить атрибуту Match элемента <NavLink>:
NavLinkMatch.All: NavLink активна при совпадении с текущим URL-адресом, игнорируя строку запроса и фрагмент. Чтобы включить сопоставление по строке запроса/фрагменту, используйте переключатель Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragmentAppContext, установленный на true.
NavLinkMatch.Prefix (по умолчанию) NavLink активен, если он соответствует любому префиксу текущего URL-адреса.
Существует два параметра NavLinkMatch, которые можно назначить атрибуту Match элемента <NavLink>:
NavLinkMatch.All: NavLink активна при совпадении всего текущего URL-адреса, включая строку запроса и фрагмент.
NavLinkMatch.Prefix (по умолчанию) NavLink активен, если он соответствует любому префиксу текущего URL-адреса.
В предыдущем примере HomeNavLinkhref="" совпадает с домашним URL-адресом и получает только класс CSS active по базовому пути приложения по умолчанию (/). Второй NavLink получает класс active, когда пользователь посещает любой URL-адрес с префиксом component (например, /component и /component/another-segment).
Для применения пользовательской логики сопоставления создайте подкласс NavLink и переопределите его метод ShouldMatch. Верните true из метода, если вы хотите применить класс CSS active:
public class CustomNavLink : NavLink
{
protected override bool ShouldMatch(string currentUriAbsolute)
{
// Custom matching logic
}
}
Дополнительные атрибуты компонента NavLink передаются в отображаемый тег привязки. В следующем примере компонент NavLink включает атрибут target.
В связи с тем, как 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 Записи компонентов можно динамически создавать из компонентов приложения с помощью отражения. В следующем примере показан общий подход к дальнейшей настройке.
Для следующей демонстрации для компонентов приложения используется согласованное стандартное соглашение об именовании:
Имена файлов маршрутизируемых компонентов используют регистр Pascal†, например Pages/ProductDetail.razor.
Пути к файлам маршрутизируемого компонента соответствуют их URL-адресам в формате 'kebab case', с дефисами, разделяющими слова в шаблоне маршрута компонента. Например, компонент ProductDetail с шаблоном маршрута /product-detail (@page "/product-detail") запрашивается в браузере по относительному URL-адресу /product-detail.
†Регистр Pascal (верхний горбатый регистр) — это соглашение об именовании без пробелов и знаков препинания, где все слова, включая первое, пишутся с прописной буквы.
'Kebab case — это соглашение об именовании без пробелов и препинания, которое использует строчные буквы и дефисы между словами.
В разметке компонента Razor (NavMenu) на странице по умолчанию NavMenu.razor компоненты Home добавляются из коллекции:
Приведенный выше пример не содержит следующие страницы в отрисованном списке компонентов:
Home страница: Эта страница перечислена отдельно от автоматически сгенерированных ссылок, поскольку она должна находиться в верхней части списка и устанавливать параметр Match.
Error страница ошибок: страница ошибок открывается только фреймворком и не должна быть указана.
Интеграция маршрутизации конечных точек ASP.NET Core
Этот раздел относится к Blazor Web Appсистемам, работающим через цепь.
Этот раздел относится к приложениям Blazor Server.
A Blazor Web App интегрируется в маршрутизацию конечных точек ASP.NET Core. Приложение ASP.NET Core настроено на прием входящих подключений для интерактивных компонентов с MapRazorComponents в файле Program. Корневой компонент по умолчанию (первый загруженный компонент) — это App компонент (App.razor):
app.MapRazorComponents<App>();
Blazor Server интегрирован с функцией маршрутизации конечных точек ASP.NET Core. Приложение ASP.NET Core настроено для приема входящих подключений для интерактивных компонентов через MapBlazorHub в файле Program.
Blazor Server интегрирован с функцией маршрутизации конечных точек ASP.NET Core. Приложение ASP.NET Core сконфигурировано для принятия входящих подключений для интерактивных компонентов с помощью MapBlazorHub в Startup.Configure.
Типичная конфигурация — маршрутизация всех запросов на страницу Razor, которая выступает в качестве узла для серверной части приложения Blazor Server. По соглашению страница узла обычно называется _Host.cshtml и находится в папке Pages приложения.
Маршрут, указанный в файле узла, называется резервным маршрутом, так как он работает с низким приоритетом в соответствии с правилами маршрутизации. Резервный маршрут используется, когда другие маршруты не сопоставляются. Это позволяет приложению использовать другие контроллеры и страницы, не мешая маршрутизации компонента в приложении Blazor Server.
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Отзыв о
ASP.NET Core
ASP.NET Core
— это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв: