Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Примечание.
Размещенные Blazor WebAssembly решения остаются поддерживаемыми, но шаблон проекта был удален и больше не поддерживается в .NET 8 или более поздней версии. Эта статья отображается в оглавлении до .NET 7 для справки, но обратите внимание, что .NET 7 — это выпуск с обычным сроком поддержки, который более не поддерживается.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core.
В этой статье описываются Razor сценарии интеграции компонентов для размещенных Blazor WebAssembly приложений, включая предварительный рендеринг Razor компонентов на сервере.
Внимание
Изменения платформы в ASP.NET Core привели к различным наборам инструкций в этой статье. Прежде чем использовать инструкции этой статьи, убедитесь, что селектор версий документов в верхней части этой статьи соответствует версии ASP.NET Core, которую вы планируете использовать для приложения.
Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.
Конфигурация решения
Конфигурация предварительной отрисовки
Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:
Разместите приложение Blazor WebAssembly в приложении ASP.NET Core. Вы можете добавить изолированное приложение Blazor WebAssembly в решение ASP.NET Core или использовать размещенное приложение Blazor WebAssembly, созданное из Blazor WebAssembly шаблона проекта, с помощью параметра размещения:
- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
BlazorHosted
. - Командная оболочка Visual Studio Code или .NET CLI:
dotnet new blazorwasm -ho
(используйте параметр-ho|--hosted
). Используйте параметр-o|--output {LOCATION}
, чтобы создать папку для решения и задать пространства имен проекта для решения. В примерах, используемых в этой статье, такое решение называетсяBlazorHosted
(dotnet new blazorwasm -ho -o BlazorHosted
).
Для примеров, приведенных в этой статье, используется имя решения (имя сборки)
BlazorHosted
, размещённого на хосте. Пространством имен проекта клиента будетBlazorHosted.Client
, а пространством имен проекта сервера —BlazorHosted.Server
.- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
файл из
wwwroot/index.html
Blazor WebAssembly проекта.В проекте Clientудалите следующие строки из файла
Program.cs
:- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
Добавьте файл
_Host.cshtml
в папку Server проектаPages
. Файлы из проекта, созданного на основе шаблона Blazor Server, можно получить с помощью Visual Studio или .NET CLI. Для этого выполните в командной оболочке командуdotnet new blazorserver -o BlazorServer
(параметр-o BlazorServer
позволяет создать папку для проекта). Поместив файлы в папку Server проектаPages
, внесите в файлы следующие изменения.Внесите указанные ниже изменения в файл
_Host.cshtml
.Обновите пространство имен
Pages
в верхней части файла, чтобы оно соответствовало пространству имен для страниц приложения Server. Заполнитель{APP NAMESPACE}
в следующем примере представляет пространство имен для страниц донорского приложения, из которого взят файл_Host.cshtml
:Удалить:
- @namespace {APP NAMESPACE}.Pages
Добавить:
@namespace BlazorHosted.Server.Pages
Добавьте директиву
@using
для проекта Client в начало файла:@using BlazorHosted.Client
Обновите ссылки таблицы стилей, чтобы они указывали на таблицы стилей проекта WebAssembly. В следующем примере для проекта клиента используется пространство имен
BlazorHosted.Client
: Заполнитель{APP NAMESPACE}
представляет пространство имен донорского приложения, из которого взят файл_Host.cshtml
. Обновите вспомогательный тег компонента (<component>
) компонентаHeadOutlet
для пререндерации компонента.Удалить:
- <link href="css/site.css" rel="stylesheet" /> - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" /> - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
Добавить:
<link href="css/app.css" rel="stylesheet" /> <link href="BlazorHosted.Client.styles.css" rel="stylesheet" /> <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Примечание.
Оставьте элемент
<link>
, который запрашивает таблицу стилей Bootstrap (css/bootstrap/bootstrap.min.css
).Обновите источник скрипта Blazor, чтобы использовать скрипт Blazor WebAssembly на стороне клиента:
Удалить:
- <script src="_framework/blazor.server.js"></script>
Добавить:
<script src="_framework/blazor.webassembly.js"></script>
Обновите
render-mode
для вспомогательного тега компонента, чтобы выполнить предварительную отрисовку корневого компонентаApp
с помощью WebAssemblyPrerendered:Удалить:
- <component type="typeof(App)" render-mode="ServerPrerendered" />
Добавить:
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
Внимание
Предварительный рендеринг не поддерживается для конечных точек проверки подлинности (сегмент пути
/authentication/
). Дополнительные сведения см. в статье Сценарии обеспечения дополнительной безопасности для ASP.NET Core Blazor WebAssembly.
В файле
Program.cs
проекта Server измените резервную конечную точку, указав вместо файлаindex.html
страницу_Host.cshtml
.Удалить:
- app.MapFallbackToFile("index.html");
Добавить:
app.MapFallbackToPage("/_Host");
Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.
Запустите проект Server. Проект Blazor WebAssembly пререндерит для клиентов хостируемое приложение Server.
Настройка для внедрения Razor компонентов в страницы или представления
В следующих разделах и примерах описано внедрение компонентов Razor из приложения ClientBlazor WebAssembly в страницы или представления серверного приложения, которое требует дополнительной настройки.
Проект Server должен иметь следующие файлы и папки.
Razor Страницы
Pages/Shared/_Layout.cshtml
Pages/Shared/_Layout.cshtml.css
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/Shared/_Layout.cshtml.css
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
Чтобы получить указанные выше файлы, создайте приложение на основе шаблонов проектов ASP.NET Core любым из следующих способов:
- Новые средства для создания проектов в Visual Studio.
- Открытие командной оболочки и выполнение команды
dotnet new webapp -o {PROJECT NAME}
(Razor Pages) илиdotnet new mvc -o {PROJECT NAME}
(MVC). Параметр-o|--output
с значением для заполнителя{PROJECT NAME}
задаёт имя приложения и создает папку для этого приложения.
Обновите пространства имен в импортированном файле _ViewImports.cshtml
, чтобы они совпадали с пространствами имен, используемыми в проекте Server, который получает файлы.
Pages/_ViewImports.cshtml
(Razor страницы):
@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/_ViewImports.cshtml
(для MVC):
@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Обновите импортированный файл макета (Pages/Shared/_Layout.cshtml
для Razor Pages или Views/Shared/_Layout.cshtml
для MVC).
Сначала удалите заголовок и таблицу стилей из донорского проекта (в следующем примере — RPDonor.styles.css
). Заполнитель {PROJECT NAME}
представляет собой название приложения донорского проекта.
- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />
Включите стили проекта Client в файл макета. В следующем примере пространством имен проекта Client является BlazorHosted.Client
. В это же время можно также обновить элемент <title>
.
Поместите следующие строки в содержимое <head>
файла макета:
<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Импортированный макет содержит две ссылки навигации Home
(страница Index
) и Privacy
. Чтобы ссылки Home
указывали на размещенное приложение Blazor WebAssembly, измените гиперссылки:
- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
В файле макета MVC:
- <a class="navbar-brand" asp-area="" asp-controller="Home"
- asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
Обновите имя приложения элемента <footer>
. В следующем примере используется имя приложения BlazorHosted
:
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>
В предыдущем примере заполнитель {DATE}
представляет дату авторского права в приложении, созданном на основе шаблона проекта Razor Pages или MVC.
Чтобы ссылка Privacy
вела на страницу конфиденциальности (Razor страница), добавьте страницу конфиденциальности в проект Server.
Pages/Privacy.cshtml
в проекте Server:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
Для представления конфиденциальности на основе MVC создайте представление конфиденциальности в Server проекте.
View/Home/Privacy.cshtml
в проекте Server:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
В контроллере Home
приложения MVC реализуйте возврат представления.
Добавьте следующий код в Controllers/HomeController.cs
:
public IActionResult Privacy()
{
return View();
}
При импорте файлов из донорского приложения обязательно обновите все пространства имен в файлах, чтобы они совпадали с пространствами имен из проекта Server (например, BlazorHosted.Server
).
Импортируйте статические ресурсы в проект Server из папки wwwroot
донорского проекта:
- Папка
wwwroot/css
и содержимое - Папка
wwwroot/js
и содержимое - Папка
wwwroot/lib
и содержимое
Если донорский проект создан из шаблона проекта ASP.NET Core и вы не изменяете файлы, можно скопировать всю папку wwwroot
из донорского проекта в проект Server и удалить файл значка favicon.
Предупреждение
Избегайте размещения статического ресурса в обеих папках Client и Serverwwwroot
. Если один и тот же файл присутствует в обеих папках, создается исключение, так как статические ресурсы используют один и тот же путь к корневой папке веб-страниц. Поэтому размещайте статический ресурс в одной из папок wwwroot
, но не в обеих.
После внедрения описанной выше конфигурации внедрите компоненты Razor в страницы или представления проекта Server. Воспользуйтесь инструкциями, приведенными в следующих разделах этой статьи.
- Отрисовка компонентов на странице или в представлении с помощью тега вспомогательных компонентов
- Рендеринг компонентов на странице или представлении с помощью селектора CSS
Отображение компонентов на странице или в представлении с помощью вспомогательного средства тегов компонентов
После настройки решения, в том числе дополнительной конфигурации, вспомогательная функция тега компонента поддерживает два режима рендеринга для отрисовки компонента из приложения Blazor WebAssembly на страницу или в представление:
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы. Чтобы избежать использования полного пространства имен для компонента Counter
с вспомогательной функцией тегов компонента ({ASSEMBLY NAME}.Pages.Counter
), добавьте директиву @using
для пространства имен Pages
проекта клиента. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В проекте ServerPages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter1
. Предварительно визуализированный компонент Counter
встроен в страницу.
Параметр RenderMode настраивает одно из следующих поведений компонента:
- предварительно отрендерено на странице.
- компонент отображается как статический HTML на странице или включает необходимые сведения для начальной загрузки приложения Blazor с помощью агента пользователя.
Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Установка дочернего содержимого с помощью фрагмента рендеринга
Вспомогательная функция тега компонента не поддерживает получение делегата RenderFragment
для дочернего содержимого (например, param-ChildContent="..."
). Рекомендуется создать компонент Razor (.razor
), который будет ссылаться на тот компонент, который вы хотите отрисовать вместе с дочерним содержимым, которое вы хотите передать, а затем вызвать компонент Razor со страницы или представления.
Убедитесь, что предварительно отрисовываемые компоненты верхнего уровня не обрезаются при публикации.
Если Component Tag Helper напрямую ссылается на компонент из библиотеки, который подлежит усечению при публикации, компонент может быть обрезан во время публикации из-за отсутствия на него ссылок из кода приложения на стороне клиента. В результате компонент не будет предварительно отрисован, и в выходных данных останется пустое место. В таком случае инструктируйте средство обрезки сохранить компонент библиотеки, добавив атрибут DynamicDependency
в любой класс клиентского приложения. Чтобы сохранить компонент с именем SomeLibraryComponentToBePreserved
, добавьте следующее в любой компонент:
@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All,
typeof(SomeLibraryComponentToBePreserved))]
Предыдущий подход обычно не требуется, так как приложение, как правило, предварительно рендерит свои компоненты (которые не подвергаются обрезке), что, в свою очередь, приводит к тому, что компоненты из библиотек также не подвергаются обрезке. Используйте DynamicDependency
явным образом только для предварительной отрисовки компонента библиотеки непосредственно в том случае, если библиотека подлежит обрезке.
Отображение компонентов на странице или в представлении с помощью селектора CSS
Настроив решение, а также реализовав дополнительную конфигурацию, добавьте корневые компоненты в проект Client размещенного решения Blazor WebAssembly в файле Program.cs
. В следующем примере компонент Counter
объявляется как корневой компонент с помощью селектора CSS, который выбирает элемент с id
, соответствующим counter-component
. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В файле Program.cs
проекта Client добавьте пространство имен для компонентов проекта Razor в начало файла:
using BlazorHosted.Client.Pages;
Настроив builder
в Program.cs
, добавьте компонент Counter
в качестве корневого компонента:
builder.RootComponents.Add<Counter>("#counter-component");
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы.
В проекте ServerPages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter2
. Предварительно визуализированный компонент Counter
встроен в страницу.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Примечание.
В предыдущем примере происходит ошибка JSException, если приложение Blazor WebAssembly предварительно отрисовывается и одновременно интегрируется в приложение Razor Pages или MVC с помощью селектора CSS. Переход к одному из компонентов Client проекта Razor или переход на страницу либо представление в Server с внедренным компонентом приводит к возникновению одного или нескольких исключений JSException.
Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.
Если вы уже работали с примерами из предыдущих разделов и теперь хотите только убедиться, что селектор CSS в вашем примере приложения работает нормально, закомментируйте спецификацию корневого компонента App
в файле Client проекта Program.cs
:
- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");
Перейдите к странице или представлению с внедренным компонентом Razor, где используется селектор CSS (например, /razorpagescounter2
из предыдущего примера). Загрузится страница или представление с внедренным компонентом, и этот компонент работает как ожидалось.
Сохранять предварительно отрисованное состояние
Без сохранения предварительно отрисованного состояния все состояния, которые использовались во время предварительной отрисовки, теряются и должны быть созданы заново при полной загрузке приложения. Если какое-либо состояние настроено асинхронно, пользовательский интерфейс может мерцать, так как предварительно отрисованный пользовательский интерфейс заменяется временными заполнителями и затем полностью отрисовывается снова.
Чтобы сохранить состояние для предварительно отрисованных компонентов, используйте вспомогательный тег сохранения состояния компонента (источник справки). Добавьте тег-помощника <persist-component-state />
внутри закрывающего тега </body>
на странице _Host
в приложении, которое рендерит компоненты.
Примечание.
По документационным ссылкам на справочные материалы по .NET обычно открывается основная ветвь репозитория, представляющая текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного выпуска, используйте выпадающий список Переключения ветвей или тегов. Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
В приложениях Pages/_Host.cshtml
с предварительно подготовленным WebAssembly (Blazor) в размещённом WebAssemblyPrerendered
приложении:
<body>
...
<persist-component-state />
</body>
Решите, какое состояние следует сохранить с помощью службы PersistentComponentState. PersistentComponentState.RegisterOnPersisting регистрирует обратный вызов для сохранения состояния компонента до приостановки приложения. Состояние извлекается при возобновлении работы приложения. Выполните вызов в конце кода инициализации, чтобы избежать потенциального условия гонки во время завершения работы приложения.
В следующем примере :
- Заполнитель
{TYPE}
представляет тип сохраняемых данных (например,WeatherForecast[]
). - Заполнитель
{TOKEN}
— это строка идентификатора состояния (например,fetchdata
).
@implements IDisposable
@inject PersistentComponentState ApplicationState
...
@code {
private {TYPE} data;
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
if (!ApplicationState.TryTakeFromJson<{TYPE}>(
"{TOKEN}", out var restored))
{
data = await ...;
}
else
{
data = restored!;
}
// Call at the end to avoid a potential race condition at app shutdown
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
}
private Task PersistData()
{
ApplicationState.PersistAsJson("{TOKEN}", data);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
Следующий пример представляет собой обновленную версию компонента FetchData
в размещенном приложении Blazor WebAssembly на основе шаблона проекта Blazor. Компонент WeatherForecastPreserveState
записывает состояние прогноза погоды во время предварительного рендеринга и затем извлекает это состояние для инициализации компонента.
Вспомогательный объект тега "Persist Component State" сохраняет состояние компонента после всех вызовов компонента.
Pages/WeatherForecastPreserveState.razor
:
@page "/weather-forecast-preserve-state"
@using BlazorSample.Shared
@implements IDisposable
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState
<PageTitle>Weather Forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
nameof(forecasts), out var restored))
{
forecasts = await WeatherForecastService.GetForecastAsync(
DateOnly.FromDateTime(DateTime.Now));
}
else
{
forecasts = restored!;
}
// Call at the end to avoid a potential race condition at app shutdown
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
}
private Task PersistData()
{
ApplicationState.PersistAsJson(nameof(forecasts), forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
При инициализации компонентов с тем же состоянием, которое использовалось во время предварительной отрисовки, все ресурсоемкие шаги инициализации выполняются только один раз. Отрисованный пользовательский интерфейс также соответствует предварительно отрисованному пользовательскому интерфейсу, поэтому в браузере нет никаких мерцаний.
Сохраняемое предварительно созданное состояние передается клиенту, где оно используется для восстановления состояния компонента. Для предварительного рендеринга в размещенном Blazor WebAssembly приложении данные попадают в браузер и не должны содержать конфиденциальную, частную информацию.
Дополнительные ресурсы Blazor WebAssembly
- Управление состоянием: обработка предварительного рендеринга
- Поддержка предварительного рендеринга с отложенной загрузкой сборки
-
Razor Темы жизненного цикла компонентов, относящиеся к предварительному рендерингу
-
Инициализация компонента (
OnInitialized{Async}
) -
После отрисовки компонента (
OnAfterRender{Async}
) - Повторное подключение с отслеживанием состояния после предварительной отрисовки: хотя в содержимом раздела внимание в основном уделяется Blazor Server и подключению с отслеживанием состояния SignalR, сценарий для предварительной отрисовки в размещенных приложениях Blazor WebAssembly (WebAssemblyPrerendered) включает в себя аналогичные условия и подходы для предотвращения повторного выполнения кода разработчиком. Для сохранения состояния во время выполнения кода инициализации при предварительной отрисовке, см. раздел Сохранение состояния при предварительной отрисовке этой статьи.
- Предварительный рендеринг с использованием взаимодействия с JavaScript
-
Инициализация компонента (
- Вопросы аутентификации и авторизации, относящиеся к пререндированию
- Размещение и развертывание ASP.NET Core Blazor WebAssembly
- Обработка ошибок: предварительная отрисовка
-
OnNavigateAsync выполняется дважды при предварительной подготовке: Обработка асинхронных событий навигации с помощью
OnNavigateAsync
Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.
Конфигурация решения
Конфигурация предварительной отрисовки
Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:
Разместите приложение Blazor WebAssembly в приложении ASP.NET Core. Вы можете добавить изолированное приложение Blazor WebAssembly в решение ASP.NET Core или использовать размещенное приложение Blazor WebAssembly, созданное из Blazor WebAssembly шаблона проекта, с помощью параметра размещения:
- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
BlazorHosted
. - Командная оболочка Visual Studio Code или .NET CLI:
dotnet new blazorwasm -ho
(используйте параметр-ho|--hosted
). Используйте параметр-o|--output {LOCATION}
, чтобы создать папку для решения и задать пространства имен проекта для решения. В примерах, используемых в этой статье, такое решение называетсяBlazorHosted
(dotnet new blazorwasm -ho -o BlazorHosted
).
В примерах, используемых в этой статье, пространством имен проекта клиента будет
BlazorHosted.Client
, а пространством имен проекта сервера —BlazorHosted.Server
.- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
файл из
wwwroot/index.html
Blazor WebAssembly проекта.В проекте Clientудалите следующие строки из файла
Program.cs
:- builder.RootComponents.Add<App>("#app"); - builder.RootComponents.Add<HeadOutlet>("head::after");
Добавьте файлы
_Host.cshtml
и_Layout.cshtml
в папку Server проектаPages
. Файлы из проекта, созданного на основе шаблона Blazor Server, можно получить с помощью Visual Studio или .NET CLI. Для этого выполните в командной оболочке командуdotnet new blazorserver -o BlazorServer
(параметр-o BlazorServer
позволяет создать папку для проекта). Поместив файлы в папку Server проектаPages
, внесите в файлы следующие изменения.Внимание
Использование страницы макета (
_Layout.cshtml
) со спомогательным тегом компонента для компонента HeadOutlet является обязательным для контроля содержимого<head>
, например, заголовка страницы (компонент PageTitle) и других элементов head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.Внесите указанные ниже изменения в файл
_Layout.cshtml
.Обновите пространство имен
Pages
в верхней части файла, чтобы оно соответствовало пространству имен для страниц приложения Server. Заполнитель{APP NAMESPACE}
в следующем примере обозначает пространство имен страниц донорского приложения, предоставившего файл_Layout.cshtml
.Удалить:
- @namespace {APP NAMESPACE}.Pages
Добавить:
@namespace BlazorHosted.Server.Pages
Добавьте директиву
@using
для проекта Client в начало файла:@using BlazorHosted.Client
Обновите ссылки таблицы стилей, чтобы они указывали на таблицы стилей проекта WebAssembly. В следующем примере для проекта клиента используется пространство имен
BlazorHosted.Client
: Заполнитель{APP NAMESPACE}
представляет пространство имен донорского приложения, из которого взят файл_Layout.cshtml
. Обновите вспомогательный тег компонента (<component>
) компонентаHeadOutlet
для пререндерации компонента.Удалить:
- <link href="css/site.css" rel="stylesheet" /> - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" /> - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
Добавить:
<link href="css/app.css" rel="stylesheet" /> <link href="BlazorHosted.Client.styles.css" rel="stylesheet" /> <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Примечание.
Оставьте элемент
<link>
, который запрашивает таблицу стилей Bootstrap (css/bootstrap/bootstrap.min.css
).Обновите источник скрипта Blazor, чтобы использовать скрипт Blazor WebAssembly на стороне клиента:
Удалить:
- <script src="_framework/blazor.server.js"></script>
Добавить:
<script src="_framework/blazor.webassembly.js"></script>
В файле
_Host.cshtml
:Измените пространство имен
Pages
, чтобы оно соответствовало проекту Client. Заполнитель{APP NAMESPACE}
представляет пространство имен страниц приложения донора, которые предоставили файл_Host.cshtml
.Удалить:
- @namespace {APP NAMESPACE}.Pages
Добавить:
@namespace BlazorHosted.Client
Обновите
render-mode
для вспомогательного тега компонента, чтобы выполнить предварительную отрисовку корневого компонентаApp
с помощью WebAssemblyPrerendered:Удалить:
- <component type="typeof(App)" render-mode="ServerPrerendered" />
Добавить:
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
Внимание
Предварительный рендеринг не поддерживается для конечных точек проверки подлинности (сегмент пути
/authentication/
). Дополнительные сведения см. в статье Сценарии обеспечения дополнительной безопасности для ASP.NET Core Blazor WebAssembly.
В разделе сопоставления конечных точек для проекта Server в файле
Program.cs
укажите вместо резервного файлаindex.html
страницу_Host.cshtml
:Удалить:
- app.MapFallbackToFile("index.html");
Добавить:
app.MapFallbackToPage("/_Host");
Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.
Запустите проект Server. Проект Blazor WebAssembly пререндерит для клиентов хостируемое приложение Server.
Настройка для внедрения Razor компонентов в страницы или представления
В следующих разделах и примерах описано внедрение компонентов Razor из приложения ClientBlazor WebAssembly в страницы или представления серверного приложения, которое требует дополнительной настройки.
Проект Server должен иметь следующие файлы и папки.
Razor Страницы
Pages/Shared/_Layout.cshtml
Pages/Shared/_Layout.cshtml.css
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/Shared/_Layout.cshtml.css
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
Внимание
Использование страницы макета (_Layout.cshtml
) со спомогательным тегом компонента для компонента HeadOutlet является обязательным для контроля содержимого <head>
, например, заголовка страницы (компонент PageTitle) и других элементов head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.
Чтобы получить указанные выше файлы, создайте приложение на основе шаблонов проектов ASP.NET Core любым из следующих способов:
- Новые средства для создания проектов в Visual Studio.
- Открытие командной оболочки и выполнение команды
dotnet new webapp -o {PROJECT NAME}
(Razor Pages) илиdotnet new mvc -o {PROJECT NAME}
(MVC). Параметр-o|--output
с значением для заполнителя{PROJECT NAME}
задаёт имя приложения и создает папку для этого приложения.
Обновите пространства имен в импортированном файле _ViewImports.cshtml
, чтобы они совпадали с пространствами имен, используемыми в проекте Server, который получает файлы.
Pages/_ViewImports.cshtml
(Razor страницы):
@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/_ViewImports.cshtml
(для MVC):
@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Обновите импортированный файл макета (Pages/Shared/_Layout.cshtml
для Razor Pages или Views/Shared/_Layout.cshtml
для MVC).
Сначала удалите заголовок и таблицу стилей из донорского проекта (в следующем примере — RPDonor.styles.css
). Заполнитель {PROJECT NAME}
представляет собой название приложения донорского проекта.
- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />
Включите стили проекта Client в файл макета. В следующем примере пространством имен проекта Client является BlazorHosted.Client
. В это же время можно также обновить элемент <title>
.
Поместите следующие строки в содержимое <head>
файла макета:
<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
Импортированный макет содержит две ссылки навигации Home
(страница Index
) и Privacy
. Чтобы ссылки Home
указывали на размещенное приложение Blazor WebAssembly, измените гиперссылки:
- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
В файле макета MVC:
- <a class="navbar-brand" asp-area="" asp-controller="Home"
- asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
Обновите имя приложения элемента <footer>
. В следующем примере используется имя приложения BlazorHosted
:
- © {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ © {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>
В предыдущем примере заполнитель {DATE}
представляет дату авторского права в приложении, созданном на основе шаблона проекта Razor Pages или MVC.
Чтобы ссылка Privacy
вела на страницу конфиденциальности (Razor страница), добавьте страницу конфиденциальности в проект Server.
Pages/Privacy.cshtml
в проекте Server:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
Для представления конфиденциальности на основе MVC создайте представление конфиденциальности в Server проекте.
View/Home/Privacy.cshtml
в проекте Server:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
В контроллере Home
приложения MVC реализуйте возврат представления.
Добавьте следующий код в Controllers/HomeController.cs
:
public IActionResult Privacy()
{
return View();
}
При импорте файлов из донорского приложения обязательно обновите все пространства имен в файлах, чтобы они совпадали с пространствами имен из проекта Server (например, BlazorHosted.Server
).
Импортируйте статические ресурсы в проект Server из папки wwwroot
донорского проекта:
- Папка
wwwroot/css
и содержимое - Папка
wwwroot/js
и содержимое - Папка
wwwroot/lib
и содержимое
Если донорский проект создан из шаблона проекта ASP.NET Core и вы не изменяете файлы, можно скопировать всю папку wwwroot
из донорского проекта в проект Server и удалить файл значка favicon.
Предупреждение
Избегайте размещения статического ресурса в обеих папках Client и Serverwwwroot
. Если один и тот же файл присутствует в обеих папках, создается исключение, так как статический ресурс в каждой из папок использует один и тот же путь к корневой папке веб-страниц. Поэтому статический ресурс следует размещать только в одной папке, указанной в wwwroot
, а не в обеих.
После внедрения описанной выше конфигурации внедрите компоненты Razor в страницы или представления проекта Server. Воспользуйтесь инструкциями, приведенными в следующих разделах этой статьи.
- Отрисовка компонентов на странице или в представлении с помощью тега вспомогательных компонентов
- Рендеринг компонентов на странице или представлении с помощью селектора CSS
Отображение компонентов на странице или в представлении с помощью вспомогательного средства тегов компонентов
После настройки решения, в том числе дополнительной конфигурации, вспомогательная функция тега компонента поддерживает два режима рендеринга для отрисовки компонента из приложения Blazor WebAssembly на страницу или в представление:
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы. Чтобы избежать использования полного пространства имен для компонента Counter
с вспомогательной функцией тегов компонента ({ASSEMBLY NAME}.Pages.Counter
), добавьте директиву @using
для пространства имен Pages
проекта клиента. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В проекте ServerPages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter1
. Предварительно визуализированный компонент Counter
встроен в страницу.
Параметр RenderMode настраивает одно из следующих поведений компонента:
- предварительно отрендерено на странице.
- компонент отображается как статический HTML на странице или включает необходимые сведения для начальной загрузки приложения Blazor с помощью агента пользователя.
Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Установка дочернего содержимого с помощью фрагмента рендеринга
Вспомогательная функция тега компонента не поддерживает получение делегата RenderFragment
для дочернего содержимого (например, param-ChildContent="..."
). Рекомендуется создать компонент Razor (.razor
), который будет ссылаться на тот компонент, который вы хотите отрисовать вместе с дочерним содержимым, которое вы хотите передать, а затем вызвать компонент Razor со страницы или представления.
Убедитесь, что предварительно обработанные компоненты верхнего уровня не удаляются при публикации.
Если Component Tag Helper напрямую ссылается на компонент из библиотеки, который подлежит усечению при публикации, компонент может быть обрезан во время публикации из-за отсутствия на него ссылок из кода приложения на стороне клиента. В результате компонент не будет предварительно отрисован, и в выходных данных останется пустое место. В таком случае инструктируйте средство обрезки сохранить компонент библиотеки, добавив атрибут DynamicDependency
в любой класс клиентского приложения. Чтобы сохранить компонент с именем SomeLibraryComponentToBePreserved
, добавьте следующее в любой компонент:
@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All,
typeof(SomeLibraryComponentToBePreserved))]
Предыдущий подход обычно не требуется, так как приложение, как правило, предварительно рендерит свои компоненты (которые не подвергаются обрезке), что, в свою очередь, приводит к тому, что компоненты из библиотек также не подвергаются обрезке. Используйте DynamicDependency
явно только для предварительного рендеринга компонента библиотеки непосредственно в том случае, если библиотека подлежит триммингу.
Отображение компонентов на странице или в представлении с помощью селектора CSS
Настроив решение, а также реализовав дополнительную конфигурацию, добавьте корневые компоненты в проект Client размещенного решения Blazor WebAssembly в файле Program.cs
. В следующем примере компонент Counter
объявляется как корневой компонент с помощью селектора CSS, который выбирает элемент с id
, соответствующим counter-component
. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В файле Program.cs
проекта Client добавьте пространство имен для компонентов проекта Razor в начало файла:
using BlazorHosted.Client.Pages;
Настроив builder
в Program.cs
, добавьте компонент Counter
в качестве корневого компонента:
builder.RootComponents.Add<Counter>("#counter-component");
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы.
В проекте ServerPages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter2
. Предварительно визуализированный компонент Counter
встроен в страницу.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Примечание.
В предыдущем примере происходит ошибка JSException, если приложение Blazor WebAssembly предварительно отрисовывается и одновременно интегрируется в приложение Razor Pages или MVC с помощью селектора CSS. Переход к одному из компонентов проекта Client или переход на страницу либо представление Server с внедренным компонентом приводит к возникновению одного или нескольких исключений JSException.
Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.
Если вы уже работали с примерами из предыдущих разделов и теперь хотите только убедиться, что селектор CSS в вашем примере приложения работает нормально, закомментируйте спецификацию корневого компонента App
в файле Client проекта Program.cs
:
- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");
Перейдите к странице или представлению с внедренным компонентом Razor, где используется селектор CSS (например, /razorpagescounter2
из предыдущего примера). Загрузится страница или представление с внедренным компонентом, и этот компонент работает как ожидалось.
Сохранять предварительно отрисованное состояние
Без сохранения предварительно отрисованного состояния все состояния, которые использовались во время предварительной отрисовки, теряются и должны быть созданы заново при полной загрузке приложения. Если какое-либо состояние настроено асинхронно, пользовательский интерфейс может мерцать, так как предварительно отрисованный пользовательский интерфейс заменяется временными заполнителями и затем полностью отрисовывается снова.
Для решения этих проблем Blazor поддерживает сохранение состояния на странице, отрисованной заранее, с помощью вспомогательного тега "Сохранение состояния компонента". Добавьте тег вспомогательного тега <persist-component-state />
внутрь закрывающего тега </body>
.
Pages/_Layout.cshtml
:
<body>
...
<persist-component-state />
</body>
Решите, какое состояние следует сохранить с помощью службы PersistentComponentState. PersistentComponentState.RegisterOnPersisting регистрирует обратный вызов для сохранения состояния компонента до приостановки приложения. Состояние извлекается при возобновлении работы приложения. Выполните вызов в конце кода инициализации, чтобы избежать потенциального условия гонки во время завершения работы приложения.
Следующий пример представляет собой обновленную версию компонента FetchData
в размещенном приложении Blazor WebAssembly на основе шаблона проекта Blazor. Компонент WeatherForecastPreserveState
записывает состояние прогноза погоды во время предварительного рендеринга и затем извлекает это состояние для инициализации компонента.
Вспомогательный объект тега "Persist Component State" сохраняет состояние компонента после всех вызовов компонента.
Pages/WeatherForecastPreserveState.razor
:
@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState
<PageTitle>Weather Forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
nameof(forecasts), out var restored))
{
forecasts =
await WeatherForecastService.GetForecastAsync(DateTime.Now);
}
else
{
forecasts = restored!;
}
// Call at the end to avoid a potential race condition at app shutdown
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
}
private Task PersistData()
{
ApplicationState.PersistAsJson(nameof(forecasts), forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
persistingSubscription.Dispose();
}
}
При инициализации компонентов с тем же состоянием, которое использовалось во время предварительной отрисовки, все ресурсоемкие шаги инициализации выполняются только один раз. Отрисованный пользовательский интерфейс также соответствует предварительно отрисованному пользовательскому интерфейсу, поэтому в браузере нет никаких мерцаний.
Сохраняемое предварительно созданное состояние передается клиенту, где оно используется для восстановления состояния компонента. Для предварительного рендеринга в размещенном Blazor WebAssembly приложении данные попадают в браузер и не должны содержать конфиденциальную, частную информацию.
Дополнительные ресурсы Blazor WebAssembly
- Управление состоянием: обработка предварительного рендеринга
- Поддержка предварительного рендеринга с отложенной загрузкой сборки
-
Razor Темы жизненного цикла компонентов, относящиеся к предварительному рендерингу
-
Инициализация компонента (
OnInitialized{Async}
) -
После отрисовки компонента (
OnAfterRender{Async}
) - Повторное подключение с отслеживанием состояния после предварительной отрисовки: хотя в содержимом раздела внимание в основном уделяется Blazor Server и подключению с отслеживанием состояния SignalR, сценарий для предварительной отрисовки в размещенных приложениях Blazor WebAssembly (WebAssemblyPrerendered) включает в себя аналогичные условия и подходы для предотвращения повторного выполнения кода разработчиком. Для сохранения состояния во время выполнения кода инициализации при предварительной отрисовке, см. раздел Сохранение состояния при предварительной отрисовке этой статьи.
- Предварительный рендеринг с использованием взаимодействия с JavaScript
-
Инициализация компонента (
- Аспекты проверки подлинности и авторизации, относящиеся к предварительному рендерингу
- Размещение и развертывание ASP.NET Core Blazor WebAssembly
Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.
Конфигурация решения
Конфигурация предварительной отрисовки
Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:
Разместите приложение Blazor WebAssembly в приложении ASP.NET Core. Вы можете добавить изолированное приложение Blazor WebAssembly в решение ASP.NET Core или использовать размещенное приложение Blazor WebAssembly, созданное из Blazor WebAssembly шаблона проекта, с помощью параметра размещения:
- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
BlazorHosted
. - Командная оболочка Visual Studio Code или .NET CLI:
dotnet new blazorwasm -ho
(используйте параметр-ho|--hosted
). Используйте параметр-o|--output {LOCATION}
, чтобы создать папку для решения и задать пространства имен проекта для решения. В примерах, используемых в этой статье, такое решение называетсяBlazorHosted
(dotnet new blazorwasm -ho -o BlazorHosted
).
В примерах, используемых в этой статье, пространством имен проекта клиента будет
BlazorHosted.Client
, а пространством имен проекта сервера —BlazorHosted.Server
.- Visual Studio: в диалоговом окне Дополнительные сведения установите флажок Размещено в ASP.NET Core при создании приложения Blazor WebAssembly. В примерах, используемых в этой статье, такое решение называется
файл из
wwwroot/index.html
Blazor WebAssembly проекта.В проекте Clientудалите следующую строку из файла
Program.cs
:- builder.RootComponents.Add<App>("#app");
Добавьте файл
Pages/_Host.cshtml
в папку Server проектаPages
. Файл_Host.cshtml
можно получить из проекта, созданного на основе шаблона Blazor Server, выполнив в командной оболочке командуdotnet new blazorserver -o BlazorServer
(параметр-o BlazorServer
создает папку для проекта). Поместив файлPages/_Host.cshtml
в проект Server размещенного решения Blazor WebAssembly, внесите в файл следующие изменения:Задайте директиву
@using
для проекта Client (например,@using BlazorHosted.Client
).Обновите ссылки таблицы стилей, чтобы они указывали на таблицы стилей проекта WebAssembly. В следующем примере пространством имен проекта клиента является
BlazorHosted.Client
:- <link href="css/site.css" rel="stylesheet" /> - <link href="_content/BlazorServer/_framework/scoped.styles.css" rel="stylesheet" /> + <link href="css/app.css" rel="stylesheet" /> + <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
Примечание.
Оставьте элемент
<link>
, который запрашивает таблицу стилей Bootstrap (css/bootstrap/bootstrap.min.css
).Обновите
render-mode
для вспомогательного тега компонента, чтобы выполнить предварительную отрисовку корневого компонентаApp
с помощью WebAssemblyPrerendered:- <component type="typeof(App)" render-mode="ServerPrerendered" /> + <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
Обновите источник скрипта Blazor, чтобы использовать скрипт Blazor WebAssembly на стороне клиента:
- <script src="_framework/blazor.server.js"></script> + <script src="_framework/blazor.webassembly.js"></script>
В методе
Startup.Configure
проекта Server измените значение резервной точки, указав вместо файлаindex.html
страницу_Host.cshtml
.Startup.cs
:- endpoints.MapFallbackToFile("index.html"); + endpoints.MapFallbackToPage("/_Host");
Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.
Запустите проект Server. Проект Blazor WebAssembly пререндерит для клиентов хостируемое приложение Server.
Настройка для внедрения Razor компонентов в страницы или представления
В следующих разделах и примерах этой статьи для внедрения Razor компонентов клиентского Blazor WebAssembly приложения в страницы или представления серверного приложения требуется дополнительная настройка.
Используйте файл по умолчанию Razor Pages или файл макета MVC в проекте Server. Проект Server должен иметь следующие файлы и папки.
Razor Страницы
Pages/Shared/_Layout.cshtml
Pages/_ViewImports.cshtml
Pages/_ViewStart.cshtml
MVC:
Views/Shared/_Layout.cshtml
Views/_ViewImports.cshtml
Views/_ViewStart.cshtml
Получите предшествующие файлы из приложения, созданного на основе шаблона проекта Razor Pages или MVC. Дополнительные сведения см. в статье Учебник. Начало работы с Razor Pages в ASP.NET Core или Начало работы с ASP.NET Core MVC.
Обновите пространства имен в импортированном файле _ViewImports.cshtml
, чтобы они совпадали с пространствами имен, используемыми в проекте Server, который получает файлы.
Обновите импортированный файл макета (_Layout.cshtml
), чтобы включить в него стили проекта Client. В следующем примере пространством имен проекта Client является BlazorHosted.Client
. В это же время можно также обновить элемент <title>
.
Pages/Shared/_Layout.cshtml
(Razor страницы) или Views/Shared/_Layout.cshtml
(MVC):
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>@ViewData["Title"] - DonorProject</title>
+ <title>@ViewData["Title"] - BlazorHosted</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
+ <link href="css/app.css" rel="stylesheet" />
+ <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>
Импортированный макет содержит ссылки навигации Home
и Privacy
. Чтобы ссылка Home
указывала на размещенное приложение Blazor WebAssembly, измените гиперссылку:
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
В файле макета MVC:
- <a class="nav-link text-dark" asp-area="" asp-controller="Home"
- asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>
Чтобы ссылка Privacy
вела на страницу конфиденциальности, добавьте страницу конфиденциальности в проект Server.
Pages/Privacy.cshtml
в проекте Server:
@page
@model BlazorHosted.Server.Pages.PrivacyModel
@{
}
<h1>Privacy Policy</h1>
Если вы предпочитаете представление конфиденциальности на основе MVC, создайте его в проекте Server.
View/Home/Privacy.cshtml
:
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
В контроллере Home
верните представление (view).
Controllers/HomeController.cs
:
public IActionResult Privacy()
{
return View();
}
Импортируйте статические ресурсы в проект Server из папки wwwroot
донорского проекта:
- Папка
wwwroot/css
и содержимое - Папка
wwwroot/js
и содержимое - Папка
wwwroot/lib
и содержимое
Если донорский проект создан из шаблона проекта ASP.NET Core и вы не изменяете файлы, можно скопировать всю папку wwwroot
из донорского проекта в проект Server и удалить файл значка favicon.
Предупреждение
Избегайте размещения статического ресурса в обеих папках Client и Serverwwwroot
. Если один и тот же файл присутствует в обеих папках, создается исключение, так как статический ресурс в каждой из папок использует один и тот же путь к корневой папке веб-страниц. Поэтому статический ресурс следует размещать только в одной папке, указанной в wwwroot
, а не в обеих.
Отображение компонентов на странице или в представлении с помощью вспомогательного средства тегов компонентов
После настройки решения, в том числе дополнительной конфигурации, вспомогательная функция тега компонента поддерживает два режима рендеринга для отрисовки компонента из приложения Blazor WebAssembly на страницу или в представление:
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы. Чтобы избежать использования полного пространства имен для компонента Counter
с вспомогательной функцией тегов компонента ({ASSEMBLY NAME}.Pages.Counter
), добавьте директиву @using
для пространства имен Pages
проекта клиента. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В проекте ServerPages/RazorPagesCounter1.cshtml
:
@page
@using BlazorHosted.Client.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter1
. Предварительно визуализированный компонент Counter
встроен в страницу.
Параметр RenderMode настраивает одно из следующих поведений компонента:
- предварительно отрендерено на странице.
- компонент отображается как статический HTML на странице или включает необходимые сведения для начальной загрузки приложения Blazor с помощью агента пользователя.
Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Отображение компонентов на странице или в представлении с помощью селектора CSS
Настроив решение, а также выполнив дополнительную конфигурацию, добавьте корневые компоненты в проект Client размещенного решения Blazor WebAssembly в Program.cs
. В следующем примере компонент Counter
объявляется как корневой компонент с помощью селектора CSS, который выбирает элемент с id
, соответствующим counter-component
. В следующем примере пространством имен проекта Client является BlazorHosted.Client
.
В файле Program.cs
проекта Client добавьте пространство имен для компонентов проекта Razor в начало файла:
using BlazorHosted.Client.Pages;
Настроив builder
в Program.cs
, добавьте компонент Counter
в качестве корневого компонента:
builder.RootComponents.Add<Counter>("#counter-component");
В следующем примере Pages Razor компонент Counter
отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы.
В проекте ServerPages/RazorPagesCounter2.cshtml
:
@page
<div id="counter-component">Loading...</div>
@section Scripts {
<script src="_framework/blazor.webassembly.js"></script>
}
Запустите проект Server. Перейдите на страницу Razor по адресу /razorpagescounter2
. Предварительно визуализированный компонент Counter
встроен в страницу.
В зависимости от упорядочения страниц макета в приложении и статических ресурсов, используемых компонентами в приложении, возможно, придется выполнить дополнительные действия. Как правило, скрипты добавляются в раздел отрисовки Scripts
представления или страницы, а таблицы стилей добавляются в содержимое элемента <head>
макета.
Примечание.
В предыдущем примере выбрасывается исключение JSException, если приложение Blazor WebAssembly предварительно отрисовывается и интегрируется в приложение Razor Pages или MVC одновременно с селектором CSS. При переходе к одному из компонентов Client проекта Razor появляется следующее исключение:
Microsoft.JSInterop.JSException: не удалось найти элемент, соответствующий селектору #counter-component.
Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.
Дополнительные ресурсы Blazor WebAssembly
- Управление состоянием: обработка предварительного рендеринга
- Поддержка предварительного рендеринга с отложенной загрузкой сборки
-
Razor Темы жизненного цикла компонентов, относящиеся к предварительному рендерингу
-
Инициализация компонента (
OnInitialized{Async}
) -
После отрисовки компонента (
OnAfterRender{Async}
) - Повторное подключение с отслеживанием состояния после предварительной отрисовки: хотя в содержимом раздела внимание в основном уделяется Blazor Server и подключению с отслеживанием состояния SignalR, сценарий для предварительной отрисовки в размещенных приложениях Blazor WebAssembly (WebAssemblyPrerendered) включает в себя аналогичные условия и подходы для предотвращения повторного выполнения кода разработчиком. Для сохранения состояния во время выполнения кода инициализации при предварительной отрисовке, см. раздел Сохранение состояния при предварительной отрисовке этой статьи.
- Предварительный рендеринг с использованием взаимодействия с JavaScript
-
Инициализация компонента (
- Субъекты аутентификации и авторизации, относящиеся к пререндированию
- Размещение и развертывание ASP.NET Core Blazor WebAssembly
Интеграция Razor компонентов в Razor приложения Pages или MVC в контексте размещенного Blazor WebAssemblyрешения поддерживается в ASP.NET Core в .NET 5 или более поздней версии. Выберите вариант этой статьи для версии .NET 5 или более поздней.
ASP.NET Core