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

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

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

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

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

  1. Разместите приложение Blazor WebAssembly в приложении ASP.NET Core. Вы можете добавить изолированное приложение Blazor WebAssembly в решение ASP.NET Core или использовать размещенное приложение Blazor WebAssembly, созданное из Blazor WebAssembly шаблона проекта, с помощью параметра размещения:

    • Visual Studio: установите флажок возле параметра Расширенный > ASP.NET Core Hosted (С размещением в 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 WebAssembly Client .

  3. В проекте Client удалите следующую строку в Program.Main (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. Запустите проект 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 или Начало работы с MVC ASP.NET Core.

Обновите пространства имен в импортированном файле _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.ico.

Примечание

Если проекты Client и Server содержат один и тот же статический ресурс в папках wwwroot (например, favicon.ico), возникает исключение, так как статический ресурс в каждой папке использует один и тот же путь к корневому каталогу:

Статический ресурс ...\favicon.ico имеет конфликтующий путь к корневому каталогу /wwwroot/favicon.ico с файлом проекта wwwroot\favicon.ico.

Поэтому статический ресурс следует размещать только в одной из папок wwwroot.

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

После настройки решения, в том числе дополнительной конфигурации, вспомогательная функция тега компонента поддерживает два режима рендеринга для отрисовки компонента из приложения Blazor WebAssembly на страницу или в представление:

В следующем примере Razor Pages компонент Counter отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы. Чтобы избежать использования полного пространства имен для компонента Counter с вспомогательной функцией тегов компонента ({APP ASSEMBLY}.Pages.Counter), добавьте директиву @using для пространства имен Pages проекта клиента. В следующем примере пространством имен проекта Client является BlazorHosted.Client.

В проекте Server Pages/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.Main. В следующем примере компонент Counter объявляется как корневой компонент с помощью селектора CSS, который выбирает элемент с id, соответствующим counter-component. В следующем примере пространством имен проекта Client является BlazorHosted.Client.

В файле Program.cs проекта Client добавьте пространство имен для компонентов проекта Razor в начало файла:

+ using BlazorHosted.Client.Pages;

Настроив builder в Program.Main, добавьте компонент Counter в качестве корневого компонента:

+ builder.RootComponents.Add<Counter>("#counter-component");

В следующем примере Razor Pages компонент Counter отрисовывается на странице. Чтобы сделать компонент интерактивным, сценарий Blazor WebAssembly добавляется в раздел отображения страницы.

В проекте Server Pages/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.

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

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

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

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

Параметр Configuration

Существующее приложение 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.Configure Startup.cs добавьте маршрут с низким приоритетом для страницы _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.Configure Startup.cs добавьте маршрут с низким приоритетом для действия контроллера, которое возвращает представление _Host:

    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 Server