Компоненты Razor для предварительной визуализации и интеграции ASP.NET Core

Примечание.

Это не последняя версия этой статьи. Последняя версия этой статьи см. в версии .NET 7.

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

Важно!

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

Компоненты Razor можно интегрировать в приложения Razor Pages и MVC в размещенном решенииBlazor WebAssembly. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Конфигурация решения

Конфигурация предварительной отрисовки

Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:

  1. Разместите приложение 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.

  2. wwwroot/index.html Удалите файл из Blazor WebAssemblyClient проекта.

  3. В проекте Clientудалите следующие строки из файла Program.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. Добавьте файл _Host.cshtml в папку Pages проекта Server. Файлы из проекта, созданного на основе шаблона Blazor Server, можно получить с помощью Visual Studio или .NET CLI. Для этого выполните в командной оболочке команду dotnet new blazorserver -o BlazorServer (параметр -o BlazorServer позволяет создать папку для проекта). Поместив файлы в папку Pages проекта Server, внесите в файлы следующие изменения.

    Внесите указанные ниже изменения в файл _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.

  5. В файле Program.cs проекта Server измените резервную конечную точку, указав вместо файла index.html страницу _Host.cshtml.

    Удалить:

    - app.MapFallbackToFile("index.html");
    

    Добавьте следующие пакеты:

    app.MapFallbackToPage("/_Host");
    
  6. Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.

  7. Запустите проект Server. Проект Server предварительно отрисовывает для клиентов размещенное приложение Blazor WebAssembly.

Конфигурация для внедрения компонентов Razor в страницы и представления

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

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

Razor Pages:

  • 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) или 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:

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {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 на страницу или в представление:

В следующем примере Razor Pages компонент 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 из страницы или представления.

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

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

В следующем примере Razor Pages компонент 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. Переход к одному из компонентов Razor проекта Client или переход на страницу либо представление в Server с внедренным компонентом приводит к возникновению одного или нескольких исключений JSException.

Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.

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

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

Перейдите к странице или представлению с внедренным компонентом Razor, где используется селектор CSS (например, /razorpagescounter2 из предыдущего примера). Загрузится страница или представление с внедренным компонентом, который должен нормально работать.

Компоненты Razor можно интегрировать в приложения MVC и Razor Pages. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Настроив проект, следуйте рекомендациям в следующих разделах в зависимости от требований проекта:

Настройка

Используйте следующие рекомендации для интеграции компонентов Razor в страницы и представления существующего приложения Razor Pages или MVC.

  1. Добавьте файл импорта в корневой каталог проекта со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен проекта.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  2. В файле макета проекта (Pages/Shared/_Layout.cshtml в приложениях Razor Pages или Views/Shared/_Layout.cshtml в приложениях MVC):

    • Добавьте следующий тег <base> и вспомогательную функцию тегов компонента HeadOutlet в элемент <head>:

      <base href="~/" />
      <component type="typeof(Microsoft.AspNetCore.Components.Web.HeadOutlet)" 
          render-mode="ServerPrerendered" />
      

      Значение href (базовый путь к приложению ) в предыдущем примере предполагает, что приложение находится по корневому URL-пути (/). Если приложение является подчиненным, следуйте инструкциям в разделе Базовый путь к приложению статьи Размещение и развертывание ASP.NET Core Blazor.

      Компонент HeadOutlet используется для отрисовки содержимого head (<head>) для заголовков страниц (компонент PageTitle) и других элементов head (компонент HeadContent), заданных компонентами Razor. Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

    • Добавьте тег <script> для скрипта blazor.server.js непосредственно перед разделом отрисовки Scripts (@await RenderSectionAsync(...)):

      <script src="_framework/blazor.server.js"></script>
      

      Платформа добавляет blazor.server.js скрипт в приложение. Добавлять файл сценария blazor.server.js в приложение вручную не нужно.

    Примечание.

    Как правило, макет загружается с помощью файла _ViewStart.cshtml.

  3. Зарегистрируйте службы Blazor Server в том файле Program.cs, где регистрируются службы:

    builder.Services.AddServerSideBlazor();
    
  4. Добавьте конечную точку концентратора Blazor в конечные точки в файле Program.cs, где сопоставляются маршруты. После вызова MapRazorPages (для страниц Razor) или MapControllerRoute (для MVC) поместите следующую строку:

    app.MapBlazorHub();
    
  5. Интегрируйте компоненты в какую-либо страницу или какое-либо представление. Например, добавьте компонент Counter в папку Shared проекта.

    Pages/Shared/Counter.razor (Razor Pages) или Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    На странице Index проекта приложения Razor Pages добавьте пространство имен компонента Counter и внедрите компонент в страницу. При загрузке страницы Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

    MVC:

    В представлении Index приложения MVC добавьте пространство имен компонента Counter и внедрите компонент в представление. При загрузке представления Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

Дополнительные сведения см. в разделе Отрисовка компонентов со страницы или представления.

Использование маршрутизируемых компонентов в приложении Razor Pages

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

Чтобы обеспечить поддержку маршрутизируемых компонентов Razor в приложениях Razor Pages:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект страницу _Host со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен приложения.

    Pages/_Host.cshtml:

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    Примечание.

    В предыдущем примере предполагается, что компонент HeadOutlet и скрипт Blazor (_framework/blazor.server.js) отрисовываются макетом приложения. Дополнительные сведения см. в разделе Конфигурация.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. В конечных точках Program.cs добавьте маршрут с низким приоритетом для страницы _Host как последнюю конечную точку:

    app.MapFallbackToPage("/_Host");
    
  5. Добавьте маршрутизируемые компоненты в проект. Следующий пример представляет собой компонент RoutableCounter, основанный на компоненте Counter в шаблонах проекта Blazor.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Использование маршрутизируемых компонентов в приложении MVC

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

Для поддержки маршрутизируемых компонентов Razor в приложениях MVC сделайте следующее:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект представление _Host со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен приложения.

    Views/Home/_Host.cshtml:

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    Примечание.

    В предыдущем примере предполагается, что компонент HeadOutlet и скрипт Blazor (_framework/blazor.server.js) отрисовываются макетом приложения. Дополнительные сведения см. в разделе Конфигурация.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. Добавьте действие в контроллер Home.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. В конечных точках Program.cs добавьте маршрут с низким приоритетом для действия контроллера, которое отвечает за возврат представления _Host:

    app.MapFallbackToController("Blazor", "Home");
    
  6. Создайте папку Pages в приложении MVC и добавьте маршрутизируемые компоненты. Следующий пример представляет собой компонент RoutableCounter, основанный на компоненте Counter в шаблонах проекта Blazor.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Отрисовка компонентов со страницы или представления

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

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

Отрисовка интерактивных компонентов с отслеживанием состояния

На страницу или в представление Razor можно добавить интерактивные компоненты с отслеживанием состояния.

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

  • компонент предварительно отображается страницей или представлением;
  • исходное состояние компонента, используемое для предварительной визуализации, теряется;
  • новое состояние компонента создается при установке подключения SignalR.

Следующая страница Razor визуализирует компонент Counter.

<h1>Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Отрисовка неинтерактивных компонентов

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

<h1>Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Пространства имен компонентов

При использовании настраиваемой папки для хранения компонентов Razor проекта добавьте пространство имен, представляющее эту папку, на страницу или в представление либо в файл _ViewImports.cshtml. В следующем примере :

  • Компоненты хранятся в папке Components проекта.
  • Заполнитель {APP NAMESPACE} — это пространство имен проекта. Components отображает имя папки.
@using {APP NAMESPACE}.Components

Файл _ViewImports.cshtml находится в папке Pages приложения Razor Pages или в папке Views приложения MVC.

Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

Сохранение предварительно отрисованного состояния

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

Чтобы сохранить состояние для предварительно созданных компонентов, используйте вспомогательный компонент тега состояния сохраняемого компонента (справочный источник). Добавьте тег вспомогательного тега, <persist-component-state />внутри закрывающего </body> тега _Host страницы в приложении, которое предопределено компонентами.

Примечание.

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

В Pages/_Host.cshtml приложениях, предварительно подготовленных Blazor webAssembly (WebAssemblyPrerendered) в размещенном Blazor WebAssemblyBlazor Server приложении или ServerPrerendered в приложении:

<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()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<{TYPE}>(
            "{TOKEN}", out var restored))
        {
            data = await ...;
        }
        else
        {
            data = restored!;
        }
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("{TOKEN}", data);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

Следующий пример представляет собой обновленную версию компонента FetchData в размещенном приложении Blazor WebAssembly на основе шаблона проекта Blazor. Компонент WeatherForecastPreserveState сохраняет состояние прогноза погоды во время предварительной отрисовки, а затем получает состояние для инициализации компонента. Вспомогательная функция тега "Сохранение состояния компонента" сохраняет состояние компонента после всех вызовов компонента.

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()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
        }
        else
        {
            forecasts = restored!;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

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

Дополнительные ресурсы Blazor WebAssembly

Предопределенный размер состояния и SignalR ограничение размера сообщения

Размер большого предопределенного состояния может превышать SignalR ограничение размера сообщения канала, что приводит к следующему:

  • Не SignalR удается инициализировать канал с ошибкой на клиенте: Circuit host not initialized.
  • Диалоговое окно повторного подключения на клиенте отображается при сбое канала. Восстановление невозможно.

Чтобы устранить проблему, используйте любой из следующих подходов:

  • Уменьшите объем данных, которые вы помещаете в предварительно созданное состояние.
  • SignalR Увеличьте размер сообщения. ПРЕДУПРЕЖДЕНИЕ. Увеличение ограничения может увеличить риск атак типа "отказ в обслуживании" (DoS).

Дополнительные ресурсы Blazor Server

Компоненты Razor можно интегрировать в приложения Razor Pages и MVC в размещенном решенииBlazor WebAssembly. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Конфигурация решения

Конфигурация предварительной отрисовки

Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:

  1. Разместите приложение 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.

  2. wwwroot/index.html Удалите файл из Blazor WebAssemblyClient проекта.

  3. В проекте Clientудалите следующие строки из файла Program.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. Добавьте файлы _Host.cshtml и _Layout.cshtml в папку Pages проекта Server. Файлы из проекта, созданного на основе шаблона Blazor Server, можно получить с помощью Visual Studio или .NET CLI. Для этого выполните в командной оболочке команду dotnet new blazorserver -o BlazorServer (параметр -o BlazorServer позволяет создать папку для проекта). Поместив файлы в папку Pages проекта Server, внесите в файлы следующие изменения.

    Важно!

    Использование страницы макета (_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.

  5. В разделе сопоставления конечных точек для проекта Server в файле Program.cs укажите вместо резервного файла index.html страницу _Host.cshtml:

    Удалить:

    - app.MapFallbackToFile("index.html");
    

    Добавьте следующие пакеты:

    app.MapFallbackToPage("/_Host");
    
  6. Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.

  7. Запустите проект Server. Проект Server предварительно отрисовывает для клиентов размещенное приложение Blazor WebAssembly.

Конфигурация для внедрения компонентов Razor в страницы и представления

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

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

Razor Pages:

  • 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) или 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:

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {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 на страницу или в представление:

В следующем примере Razor Pages компонент 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 из страницы или представления.

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

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

В следующем примере Razor Pages компонент 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. Переход к одному из компонентов Razor проекта Client или переход на страницу либо представление в Server с внедренным компонентом приводит к возникновению одного или нескольких исключений JSException.

Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.

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

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

Перейдите к странице или представлению с внедренным компонентом Razor, где используется селектор CSS (например, /razorpagescounter2 из предыдущего примера). Загрузится страница или представление с внедренным компонентом, который должен нормально работать.

Компоненты Razor можно интегрировать в приложения MVC и Razor Pages. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Настроив проект, следуйте рекомендациям в следующих разделах в зависимости от требований проекта:

Настройка

Используйте следующие рекомендации для интеграции компонентов Razor в страницы и представления существующего приложения Razor Pages или MVC.

Важно!

Использование страницы макета (_Layout.cshtml) с вспомогательной функцией тега компонента для компонента HeadOutlet является обязательным условием для управления содержимым <head>, например заголовком страницы (компонент PageTitle), и другими элементами head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

  1. В файле макета проекта:

    • Добавьте следующий тег <base> и вспомогательную функцию тегов компонента HeadOutlet в элемент <head> в Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

      <base href="~/" />
      <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      Значение href (базовый путь к приложению ) в предыдущем примере предполагает, что приложение находится по корневому URL-пути (/). Если приложение является подчиненным, следуйте инструкциям в разделе Базовый путь к приложению статьи Размещение и развертывание ASP.NET Core Blazor.

      Компонент HeadOutlet используется для отрисовки содержимого head (<head>) для заголовков страниц (компонент PageTitle) и других элементов head (компонент HeadContent), заданных компонентами Razor. Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

    • Добавьте тег <script> для скрипта blazor.server.js непосредственно перед разделом отрисовки Scripts (@await RenderSectionAsync(...)) в макете приложения.

      Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

      <script src="_framework/blazor.server.js"></script>
      

      Платформа добавляет blazor.server.js скрипт в приложение. Добавлять файл сценария blazor.server.js в приложение вручную не нужно.

  2. Добавьте файл импорта в корневой каталог проекта со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен проекта.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.AspNetCore.Components.Web.Virtualization
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Зарегистрируйте службы Blazor Server в том файле Program.cs, где регистрируются службы:

    builder.Services.AddServerSideBlazor();
    
  4. Добавьте конечную точку концентратора Blazor в конечные точки в файле Program.cs, где сопоставляются маршруты.

    После вызова MapRazorPages (для страниц Razor) или MapControllerRoute (для MVC) поместите следующую строку:

    app.MapBlazorHub();
    
  5. Интегрируйте компоненты в какую-либо страницу или какое-либо представление. Например, добавьте компонент Counter в папку Shared проекта.

    Pages/Shared/Counter.razor (Razor Pages) или Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    На странице Index проекта приложения Razor Pages добавьте пространство имен компонента Counter и внедрите компонент в страницу. При загрузке страницы Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

    MVC:

    В представлении Index приложения MVC добавьте пространство имен компонента Counter и внедрите компонент в представление. При загрузке представления Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    

Дополнительные сведения см. в разделе Отрисовка компонентов со страницы или представления.

Использование маршрутизируемых компонентов в приложении Razor Pages

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

Чтобы обеспечить поддержку маршрутизируемых компонентов Razor в приложениях Razor Pages:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект страницу _Host со следующим содержимым.

    Pages/_Host.cshtml:

    @page "/blazor"
    @namespace {APP NAMESPACE}.Pages.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    В этом сценарии компоненты используют для макета общий файл _Layout.cshtml.

    Важно!

    Использование страницы макета (_Layout.cshtml) с вспомогательной функцией тега компонента для компонента HeadOutlet является обязательным условием для управления содержимым <head>, например заголовком страницы (компонент PageTitle), и другими элементами head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. В конечных точках Program.cs добавьте маршрут с низким приоритетом для страницы _Host как последнюю конечную точку:

    app.MapFallbackToPage("/_Host");
    
  5. Добавьте маршрутизируемые компоненты в проект. Следующий пример представляет собой компонент RoutableCounter, основанный на компоненте Counter в шаблонах проекта Blazor.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Использование маршрутизируемых компонентов в приложении MVC

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

Для поддержки маршрутизируемых компонентов Razor в приложениях MVC сделайте следующее:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <p role="alert">Sorry, there's nothing at this address.</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект представление _Host со следующим содержимым.

    Views/Home/_Host.cshtml:

    @namespace {APP NAMESPACE}.Views.Shared
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    @{
        Layout = "_Layout";
    }
    
    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    Для макета компоненты используют общий файл _Layout.cshtml.

    Важно!

    Использование страницы макета (_Layout.cshtml) с вспомогательной функцией тега компонента для компонента HeadOutlet является обязательным условием для управления содержимым <head>, например заголовком страницы (компонент PageTitle), и другими элементами head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. Добавьте действие в контроллер Home.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. В конечных точках Program.cs добавьте маршрут с низким приоритетом для действия контроллера, которое отвечает за возврат представления _Host:

    app.MapFallbackToController("Blazor", "Home");
    
  6. Создайте папку Pages в приложении MVC и добавьте маршрутизируемые компоненты. Следующий пример представляет собой компонент RoutableCounter, основанный на компоненте Counter в шаблонах проекта Blazor.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <PageTitle>Routable Counter</PageTitle>
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Отрисовка компонентов со страницы или представления

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

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

Отрисовка интерактивных компонентов с отслеживанием состояния

На страницу или в представление Razor можно добавить интерактивные компоненты с отслеживанием состояния.

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

  • компонент предварительно отображается страницей или представлением;
  • исходное состояние компонента, используемое для предварительной визуализации, теряется;
  • новое состояние компонента создается при установке подключения SignalR.

Следующая страница Razor визуализирует компонент Counter.

<h1>Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Важно!

Использование страницы макета (_Layout.cshtml) с вспомогательной функцией тега компонента для компонента HeadOutlet является обязательным условием для управления содержимым <head>, например заголовком страницы (компонент PageTitle), и другими элементами head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

Отрисовка неинтерактивных компонентов

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

<h1>Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Важно!

Использование страницы макета (_Layout.cshtml) с вспомогательной функцией тега компонента для компонента HeadOutlet является обязательным условием для управления содержимым <head>, например заголовком страницы (компонент PageTitle), и другими элементами head (компонент HeadContent). Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

Пространства имен компонентов

При использовании настраиваемой папки для хранения компонентов Razor проекта добавьте пространство имен, представляющее эту папку, на страницу или в представление либо в файл _ViewImports.cshtml. В следующем примере :

  • Компоненты хранятся в папке Components проекта.
  • Заполнитель {APP NAMESPACE} — это пространство имен проекта. Components отображает имя папки.
@using {APP NAMESPACE}.Components

Файл _ViewImports.cshtml находится в папке Pages приложения Razor Pages или в папке Views приложения MVC.

Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

Сохранение предварительно отрисованного состояния

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

Для решения этих проблем Blazor поддерживает состояние сохранения на предварительно отрисованной странице с помощью вспомогательной функции тега "Сохранение состояния компонента". Добавьте тег вспомогательной функции тега <persist-component-state /> в закрывающий тег </body>.

Pages/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

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

Следующий пример представляет собой обновленную версию компонента FetchData в размещенном приложении Blazor WebAssembly на основе шаблона проекта Blazor. Компонент WeatherForecastPreserveState сохраняет состояние прогноза погоды во время предварительной отрисовки, а затем получает состояние для инициализации компонента. Вспомогательная функция тега "Сохранение состояния компонента" сохраняет состояние компонента после всех вызовов компонента.

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()
    {
        persistingSubscription = 
            ApplicationState.RegisterOnPersisting(PersistForecasts);

        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            "fetchdata", out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateTime.Now);
        }
        else
        {
            forecasts = restored!;
        }
    }

    private Task PersistForecasts()
    {
        ApplicationState.PersistAsJson("fetchdata", forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

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

Дополнительные ресурсы Blazor WebAssembly

Предопределенный размер состояния и SignalR ограничение размера сообщения

Размер большого предопределенного состояния может превышать SignalR ограничение размера сообщения канала, что приводит к следующему:

  • Не SignalR удается инициализировать канал с ошибкой на клиенте: Circuit host not initialized.
  • Диалоговое окно повторного подключения на клиенте отображается при сбое канала. Восстановление невозможно.

Чтобы устранить проблему, используйте любой из следующих подходов:

  • Уменьшите объем данных, которые вы помещаете в предварительно созданное состояние.
  • SignalR Увеличьте размер сообщения. ПРЕДУПРЕЖДЕНИЕ. Увеличение ограничения может увеличить риск атак типа "отказ в обслуживании" (DoS).

Дополнительные ресурсы Blazor Server

Компоненты Razor можно интегрировать в приложения Razor Pages и MVC в размещенном решенииBlazor WebAssembly. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Конфигурация решения

Конфигурация предварительной отрисовки

Чтобы настроить предварительную отрисовку для размещенного приложения Blazor WebAssembly, сделайте следующее:

  1. Разместите приложение 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.

  2. wwwroot/index.html Удалите файл из Blazor WebAssemblyClient проекта.

  3. В проекте Clientудалите следующую строку из файла Program.cs:

    - builder.RootComponents.Add<App>("#app");
    
  4. Добавьте файл Pages/_Host.cshtml в папку Pages проекта Server. Файл _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>
      
  5. В методе Startup.Configure проекта Server измените значение резервной точки, указав вместо файла index.html страницу _Host.cshtml.

    Startup.cs:

    - endpoints.MapFallbackToFile("index.html");
    + endpoints.MapFallbackToPage("/_Host");
    
  6. Если в проектах Client и Server используется одна или несколько общих служб во время предварительной отрисовки, следует учитывать регистрацию этих служб в методе, который может вызываться из обоих проектов. Дополнительные сведения см. в статье Внедрение зависимостей Blazor ASP.NET Core.

  7. Запустите проект Server. Проект Server предварительно отрисовывает для клиентов размещенное приложение Blazor WebAssembly.

Конфигурация для внедрения компонентов Razor в страницы и представления

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

Используйте файл по умолчанию Razor Pages или файл макета MVC в проекте Server. Проект Server должен иметь следующие файлы и папки.

Razor Pages:

  • 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 Pages) или 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 верните представление.

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 на страницу или в представление:

В следующем примере Razor Pages компонент 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");

В следующем примере Razor Pages компонент 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. При переходе к одному из компонентов Razor проекта Client появляется следующее исключение:

Microsoft.JSInterop.JSException: не удалось найти элемент, соответствующий селектору #counter-component.

Это нормальное поведение, поскольку предварительная отрисовка и интеграция приложения Blazor WebAssembly с маршрутизируемыми компонентами Razor несовместимы с использованием селекторов CSS.

Компоненты Razor можно интегрировать в приложения MVC и Razor Pages. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Настроив проект, следуйте рекомендациям в следующих разделах в зависимости от требований проекта:

Настройка

Существующее приложение MVC или Razor Pages может интегрировать компоненты Razor в страницы и представления:

  1. В файле макета проекта:

    • Добавьте следующий тег <base> в элемент <head> в Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

      <base href="~/" />
      

      Значение href (базовый путь к приложению ) в предыдущем примере предполагает, что приложение находится по корневому URL-пути (/). Если приложение является подчиненным, следуйте инструкциям в разделе Базовый путь к приложению статьи Размещение и развертывание ASP.NET Core Blazor.

    • Добавьте тег <script> для скрипта blazor.server.js непосредственно перед разделом отрисовки Scripts.

      Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

          ...
          <script src="_framework/blazor.server.js"></script>
      
          @await RenderSectionAsync("Scripts", required: false)
      </body>
      

      Платформа добавляет blazor.server.js скрипт в приложение. Добавлять файл сценария blazor.server.js в приложение вручную не нужно.

  2. Добавьте файл импорта в корневой каталог проекта со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен проекта.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Зарегистрируйте службу Blazor Server в Startup.ConfigureServices.

    В Startup.cs:

    services.AddServerSideBlazor();
    
  4. Добавьте конечную точку концентратора Blazor в конечные точки (app.UseEndpoints) Startup.Configure.

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. Интегрируйте компоненты в какую-либо страницу или какое-либо представление. Например, добавьте компонент Counter в папку Shared проекта.

    Pages/Shared/Counter.razor (Razor Pages) или Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    На странице Index проекта приложения Razor Pages добавьте пространство имен компонента Counter и внедрите компонент в страницу. При загрузке страницы Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    В предыдущем примере замените заполнитель {APP NAMESPACE} пространством имен приложения.

    MVC:

    В представлении Index приложения MVC добавьте пространство имен компонента Counter и внедрите компонент в представление. При загрузке представления Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

Дополнительные сведения см. в разделе Отрисовка компонентов со страницы или представления.

Использование маршрутизируемых компонентов в приложении Razor Pages

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

Чтобы обеспечить поддержку маршрутизируемых компонентов Razor в приложениях Razor Pages:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    Примечание.

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

  3. Добавьте в проект страницу _Host со следующим содержимым.

    Pages/_Host.cshtml:

    @page "/blazor"
    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Для макета компоненты используют общий файл _Layout.cshtml.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. В конечных точках Startup.ConfigureStartup.cs добавьте маршрут с низким приоритетом для страницы _Host как последнюю конечную точку:

    endpoints.MapFallbackToPage("/_Host");
    

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. Добавьте маршрутизируемые компоненты в проект.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Использование маршрутизируемых компонентов в приложении MVC

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

Для поддержки маршрутизируемых компонентов Razor в приложениях MVC сделайте следующее:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    

    Примечание.

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

  3. Добавьте в проект представление _Host со следующим содержимым.

    Views/Home/_Host.cshtml:

    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Для макета компоненты используют общий файл _Layout.cshtml.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. Добавьте действие в контроллер Home.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. В конечных точках Startup.ConfigureStartup.cs добавьте маршрут с низким приоритетом для действия контроллера, которое возвращает представление _Host:

    endpoints.MapFallbackToController("Blazor", "Home");
    

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. Добавьте маршрутизируемые компоненты в проект.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Отрисовка компонентов со страницы или представления

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

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

Отрисовка интерактивных компонентов с отслеживанием состояния

На страницу или в представление Razor можно добавить интерактивные компоненты с отслеживанием состояния.

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

  • компонент предварительно отображается страницей или представлением;
  • исходное состояние компонента, используемое для предварительной визуализации, теряется;
  • новое состояние компонента создается при установке подключения SignalR.

Следующая страница Razor визуализирует компонент Counter.

<h1>My Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Отрисовка неинтерактивных компонентов

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

<h1>My Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Пространства имен компонентов

При использовании настраиваемой папки для хранения компонентов Razor проекта добавьте пространство имен, представляющее эту папку, на страницу или в представление либо в файл _ViewImports.cshtml. В следующем примере :

  • Компоненты хранятся в папке Components проекта.
  • Заполнитель {APP NAMESPACE} — это пространство имен проекта. Components отображает имя папки.
@using {APP NAMESPACE}.Components

Файл _ViewImports.cshtml находится в папке Pages приложения Razor Pages или в папке Views приложения MVC.

Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

Дополнительные ресурсы Blazor WebAssembly

Предопределенный размер состояния и SignalR ограничение размера сообщения

Размер большого предопределенного состояния может превышать SignalR ограничение размера сообщения канала, что приводит к следующему:

  • Не SignalR удается инициализировать канал с ошибкой на клиенте: Circuit host not initialized.
  • Диалоговое окно повторного подключения на клиенте отображается при сбое канала. Восстановление невозможно.

Чтобы устранить проблему, используйте любой из следующих подходов:

  • Уменьшите объем данных, которые вы помещаете в предварительно созданное состояние.
  • SignalR Увеличьте размер сообщения. ПРЕДУПРЕЖДЕНИЕ. Увеличение ограничения может увеличить риск атак типа "отказ в обслуживании" (DoS).

Дополнительные ресурсы Blazor Server

Интеграция компонентов Razor в приложения Razor Pages и MVC в размещенном решенииBlazor WebAssembly поддерживается в ASP.NET Core в .NET 5 или более поздней версии. Выберите вариант этой статьи для версии .NET 5 или более поздней.

Компоненты Razor можно интегрировать в приложения MVC и Razor Pages. Одновременно с отрисовкой страницы или представления можно выполнять предварительную обработку компонентов.

Предварительная отрисовка может улучшить оптимизацию для поисковых систем (SEO) за счет визуализации содержимого для первоначального ответа HTTP, который поисковые системы могут использовать для вычисления ранга страницы.

Настроив проект, следуйте рекомендациям в следующих разделах в зависимости от требований проекта:

Настройка

Существующее приложение MVC или Razor Pages может интегрировать компоненты Razor в страницы и представления:

  1. В файле макета проекта:

    • Добавьте следующий тег <base> в элемент <head> в Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

      + <base href="~/" />
      

      Значение href (базовый путь к приложению ) в предыдущем примере предполагает, что приложение находится по корневому URL-пути (/). Если приложение является подчиненным, следуйте инструкциям в разделе Базовый путь к приложению статьи Размещение и развертывание ASP.NET Core Blazor.

    • Добавьте тег <script> для скрипта blazor.server.js непосредственно перед разделом отрисовки Scripts.

      Pages/Shared/_Layout.cshtml (Razor Pages) или Views/Shared/_Layout.cshtml (MVC):

          ...
          <script src="_framework/blazor.server.js"></script>
      
          @await RenderSectionAsync("Scripts", required: false)
      </body>
      

      Платформа добавляет blazor.server.js скрипт в приложение. Добавлять файл сценария blazor.server.js в приложение вручную не нужно.

  2. Добавьте файл импорта в корневой каталог проекта со следующим содержимым. Замените заполнитель {APP NAMESPACE} пространством имен проекта.

    _Imports.razor:

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using {APP NAMESPACE}
    
  3. Зарегистрируйте службу Blazor Server в Startup.ConfigureServices.

    Startup.cs:

    services.AddServerSideBlazor();
    
  4. Добавьте конечную точку концентратора Blazor в конечные точки (app.UseEndpoints) Startup.Configure.

    Startup.cs:

    endpoints.MapBlazorHub();
    
  5. Интегрируйте компоненты в какую-либо страницу или какое-либо представление. Например, добавьте компонент Counter в папку Shared проекта.

    Pages/Shared/Counter.razor (Razor Pages) или Views/Shared/Counter.razor (MVC):

    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    

    Razor Pages:

    На странице Index проекта приложения Razor Pages добавьте пространство имен компонента Counter и внедрите компонент в страницу. При загрузке страницы Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Pages/Index.cshtml:

    @page
    @using {APP NAMESPACE}.Pages.Shared
    @model IndexModel
    @{
        ViewData["Title"] = "Home page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

    В предыдущем примере замените заполнитель {APP NAMESPACE} пространством имен приложения.

    MVC:

    В представлении Index приложения MVC добавьте пространство имен компонента Counter и внедрите компонент в представление. При загрузке представления Index компонент Counter будет предварительно отрисован на странице. В следующем примере замените заполнитель {APP NAMESPACE} пространством имен проекта.

    Views/Home/Index.cshtml:

    @using {APP NAMESPACE}.Views.Shared
    @{
        ViewData["Title"] = "Home Page";
    }
    
    <div>
        <component type="typeof(Counter)" render-mode="ServerPrerendered" />
    </div>
    

Дополнительные сведения см. в разделе Отрисовка компонентов со страницы или представления.

Использование маршрутизируемых компонентов в приложении Razor Pages

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

Чтобы обеспечить поддержку маршрутизируемых компонентов Razor в приложениях Razor Pages:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект страницу _Host со следующим содержимым.

    Pages/_Host.cshtml:

    @page "/blazor"
    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Для макета компоненты используют общий файл _Layout.cshtml.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. В конечных точках Startup.ConfigureStartup.cs добавьте маршрут с низким приоритетом для страницы _Host как последнюю конечную точку:

    endpoints.MapFallbackToPage("/_Host");
    

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
    });
    
  5. Добавьте маршрутизируемые компоненты в проект.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  6. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Использование маршрутизируемых компонентов в приложении MVC

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

Для поддержки маршрутизируемых компонентов Razor в приложениях MVC сделайте следующее:

  1. Следуйте указаниям в разделе Конфигурация.

  2. Добавьте компонент App в корневой каталог проекта со следующим содержимым.

    App.razor:

    @using Microsoft.AspNetCore.Components.Routing
    
    <Router AppAssembly="typeof(Program).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" />
        </Found>
        <NotFound>
            <h1>Page not found</h1>
            <p>Sorry, but there's nothing here!</p>
        </NotFound>
    </Router>
    
  3. Добавьте в проект представление _Host со следующим содержимым.

    Views/Home/_Host.cshtml:

    @{
        Layout = "_Layout";
    }
    
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>
    

    Для макета компоненты используют общий файл _Layout.cshtml.

    Параметр RenderMode настраивает одно из следующих поведений компонента App:

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

    Дополнительные сведения о вспомогательной функции тега компонента, в том числе о передаче параметров и конфигурации RenderMode, см. в статье Вспомогательная функция тега компонента в ASP.NET Core.

  4. Добавьте действие в контроллер Home.

    Controllers/HomeController.cs:

    public IActionResult Blazor()
    {
       return View("_Host");
    }
    
  5. В конечных точках Startup.ConfigureStartup.cs добавьте маршрут с низким приоритетом для действия контроллера, которое возвращает представление _Host:

    endpoints.MapFallbackToController("Blazor", "Home");
    

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToController("Blazor", "Home");
    });
    
  6. Добавьте маршрутизируемые компоненты в проект.

    Pages/RoutableCounter.razor:

    @page "/routable-counter"
    
    <h1>Routable Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    @code {
        private int currentCount = 0;
    
        private void IncrementCount()
        {
            currentCount++;
        }
    }
    
  7. Запустите проект и перейдите к маршрутизируемому компоненту RoutableCounter по адресу /routable-counter.

Дополнительные сведения о пространствах имен см. в разделе Пространства имен компонентов.

Отрисовка компонентов со страницы или представления

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

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

Отрисовка интерактивных компонентов с отслеживанием состояния

На страницу или в представление Razor можно добавить интерактивные компоненты с отслеживанием состояния.

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

  • компонент предварительно отображается страницей или представлением;
  • исходное состояние компонента, используемое для предварительной визуализации, теряется;
  • новое состояние компонента создается при установке подключения SignalR.

Следующая страница Razor визуализирует компонент Counter.

<h1>My Razor Page</h1>

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Отрисовка неинтерактивных компонентов

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

<h1>My Razor Page</h1>

<form>
    <input type="number" asp-for="InitialValue" />
    <button type="submit">Set initial value</button>
</form>

<component type="typeof(Counter)" render-mode="Static" 
    param-InitialValue="InitialValue" />

@functions {
    [BindProperty(SupportsGet=true)]
    public int InitialValue { get; set; }
}

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

Пространства имен компонентов

При использовании настраиваемой папки для хранения компонентов Razor проекта добавьте пространство имен, представляющее эту папку, на страницу или в представление либо в файл _ViewImports.cshtml. В следующем примере :

  • Компоненты хранятся в папке Components проекта.
  • Заполнитель {APP NAMESPACE} — это пространство имен проекта. Components отображает имя папки.
@using {APP NAMESPACE}.Components

Файл _ViewImports.cshtml находится в папке Pages приложения Razor Pages или в папке Views приложения MVC.

Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

Предопределенный размер состояния и SignalR ограничение размера сообщения

Размер большого предопределенного состояния может превышать SignalR ограничение размера сообщения канала, что приводит к следующему:

  • Не SignalR удается инициализировать канал с ошибкой на клиенте: Circuit host not initialized.
  • Диалоговое окно повторного подключения на клиенте отображается при сбое канала. Восстановление невозможно.

Чтобы устранить проблему, используйте любой из следующих подходов:

  • Уменьшите объем данных, которые вы помещаете в предварительно созданное состояние.
  • SignalR Увеличьте размер сообщения. ПРЕДУПРЕЖДЕНИЕ. Увеличение ограничения может увеличить риск атак типа "отказ в обслуживании" (DoS).

Дополнительные ресурсы Blazor Server