Создание многоразового пользовательского интерфейса с помощью проекта библиотеки классов Razor в ASP.NET Core

Автор: Рик Андерсон (Rick Anderson)

В библиотеку классов Razor (RCL) можно встроить представления Razor, страницы, контроллеры, модели страниц, компоненты Razor, компоненты представления. RCL можно упаковать и использовать повторно. Приложения могут включать RCL и переопределять содержащиеся в нем представления и страницы. При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении.

Просмотреть или скачать образец кода (как скачивать)

Создание библиотеки классов с пользовательским интерфейсом Razor

  • В Visual Studio выберите Создать проект.
  • Выберите Библиотека классов Razor > Далее.
  • Присвойте библиотеке имя (например, RazorClassLib) и щелкните Создать > Далее. Чтобы избежать конфликта имени файла с созданной библиотекой представлений, проверьте, что имя библиотеки не заканчивается на .Views.
  • Выберите целевую платформу. Установите флажок ☑ Support pages and views (Включить поддержку представлений страниц и представлений). По умолчанию поддерживаются только компоненты Razor. Выберите Создать.

По умолчанию для шаблона библиотеки классов Razor (RCL) используется разработка компонентов Razor. При выборе параметра Представления и страницы поддержки поддерживаются страницы и представления.

Добавьте файлы Razor в библиотеку RCL.

В шаблонах ASP.NET Core предполагается, что содержимое RCL находится в папке Areas. Сведения о том, как создать библиотеку RCL с содержимым в папке ~/Pages, а не ~/Areas/Pages, см. в разделе Макет страниц RCL.

Ссылка на содержимое RCL

На RCL могут ссылаться:

Переопределение представлений, частичных представлений и страниц

При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении. Например, если вы добавите WebApp1/Areas/MyFeature/Pages/Page1.cshtml в WebApp1, Page1 в WebApp1 будет иметь приоритет над Page1 в RCL.

В примере загрузки переименуйте WebApp1/Areas/MyFeature2 в WebApp1/Areas/MyFeature, чтобы задать приоритет теста.

Скопируйте частичное представление RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml в WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Обновите разметку, чтобы указать новое расположение. Скомпилируйте и запустите приложение, чтобы убедиться, что используется версия частичного представления из приложения.

Макет страниц RCL

Чтобы ссылаться на содержимое RCL так, как будто оно находится в папке Pages веб-приложения, создайте проект RCL со следующей структурой файлов:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Предположим, что RazorUIClassLib/Pages/Shared содержит два частичных файла: _Header.cshtml и _Footer.cshtml. В файл _Layout.cshtml можно добавить теги <partial>:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Добавьте файл _ViewStart.cshtml в папку Pages проекта RCL, чтобы использовать файл _Layout.cshtml из ведущего веб-приложения:

@{
    Layout = "_Layout";
}

Создание библиотеки RCL со статическими ресурсами

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

Чтобы включить сопутствующие ресурсы в библиотеку RCL, создайте папку wwwroot в библиотеке классов и добавьте в нее все необходимые файлы.

При упаковке RCL все сопутствующие ресурсы в папке wwwroot автоматически включаются в пакет.

Используйте команду dotnet pack, а не NuGet.exe версии nuget pack.

Исключение статических ресурсов

Чтобы исключить статические ресурсы, добавьте путь исключения в группу свойств $(DefaultItemExcludes) в файле проекта. Записи следует разделять точкой с запятой (;).

В следующем примере таблица стилей lib.css в папкеwwwroot не считается статическим ресурсом и не включается в опубликованную библиотеку RCL:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Интеграция с TypeScript

Чтобы включить файлы TypeScript в библиотеку RCL, выполните указанные ниже действия.

  1. Поместите файлы TypeScript (.ts) в папку, отличную от wwwroot. Например, их можно поместить в папку Client.

  2. Укажите папку wwwroot в качестве выходного пути сборки TypeScript. Задайте свойство TypescriptOutDir в группе PropertyGroup в файле проекта:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  3. Включите целевой объект TypeScript в качестве зависимости целевого объекта ResolveCurrentProjectStaticWebAssets, добавив следующий целевой объект в группу PropertyGroup в файле проекта:

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

Использование содержимого из связанной библиотеки RCL

Файлы в папке wwwroot библиотеки RCL доступны самой библиотеке RCL или использующему ее приложению по пути _content/{PACKAGE ID}/. Например, библиотека с именем сборки Razor.Class.Lib и без указания <PackageId> в файле проекта приводит к указанию пути к статическому содержимому в _content/Razor.Class.Lib/. При создании пакета NuGet имя сборки не совпадает с идентификатором пакета (<PackageId> в файле проекта библиотеки), используйте идентификатор пакета, как указано в файле проекта для {PACKAGE ID}.

Использующее библиотеку приложение ссылается на предоставляемые ею статические ресурсы с помощью тегов HTML <script>, <style>, <img> и других. Для приложения необходимо включить поддержку статических файлов в Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

Когда приложение запускается из выходного пути сборки (dotnet run), в среде разработки статические веб-ресурсы включены по умолчанию. Для поддержки ресурсов в других средах при запуске из выходного пути сборки вызовите метод UseStaticWebAssets построителя узла в файле Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

При запуске приложения из пути публикации (dotnet publish) вызывать UseStaticWebAssets не нужно.

Процесс разработки нескольких проектов

При запуске использующего библиотеку приложения происходит следующее:

  • Ресурсы RCL остаются в исходных папках. Они не перемещаются в приложение.
  • Любые изменения в папке wwwroot библиотеки RCL отражаются в приложении после перестроения RCL, причем приложение перестраивать не требуется.

При сборке библиотеки RCL создается манифест, в котором описывается расположение статических веб-ресурсов. Использующее библиотеку приложение считывает манифест во время выполнения для получения ресурсов из связанных проектов и пакетов. При добавлении нового ресурса в библиотеку RCL ее необходимо перестроить, чтобы обновить манифест. Только после этого приложение сможет получить доступ к новому ресурсу.

Публикация

При публикации приложения сопутствующие ресурсы из всех связанных проектов и пакетов копируются в папку wwwroot опубликованного приложения в папке _content/{PACKAGE ID}/. При создании пакета NuGet имя сборки не совпадает с идентификатором пакета (<PackageId> в файле проекта библиотеки), используйте идентификатор пакета, указанный в файле проекта для {PACKAGE ID} при проверке папки wwwroot для опубликованных ресурсов.

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

В библиотеку классов Razor (RCL) можно встроить представления Razor, страницы, контроллеры, модели страниц, компоненты Razor, компоненты представления. RCL можно упаковать и использовать повторно. Приложения могут включать RCL и переопределять содержащиеся в нем представления и страницы. При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении.

Просмотреть или скачать образец кода (как скачивать)

Создание библиотеки классов с пользовательским интерфейсом Razor

  • В Visual Studio в меню Файл щелкните Создать > Проект.
  • Выберите Новое веб-приложение ASP.NET Core.
  • Назовите библиотеку (например, "RazorClassLib") и нажмите кнопку ОК. Чтобы избежать конфликта имени файла с созданной библиотекой представлений, проверьте, что имя библиотеки не заканчивается на .Views.
  • Убедитесь, что выбрано ASP.NET Core 2.1 или более поздней версии.
  • Выберите Библиотека классов Razor > ОК.

Библиотека RCL имеет следующий файл проекта:

<Project Sdk="Microsoft.NET.Sdk.Razor">

    <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
    </PropertyGroup>

    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>


</Project>

Добавьте файлы Razor в библиотеку RCL.

В шаблонах ASP.NET Core предполагается, что содержимое RCL находится в папке Areas. Сведения о том, как создать библиотеку RCL с содержимым в папке ~/Pages, а не ~/Areas/Pages, см. в разделе Макет страниц RCL.

Ссылка на содержимое RCL

На RCL могут ссылаться:

Пошаговое руководство. Создание проекта RCL и его использование в проекте Razor Pages

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

Тестирование приложения загрузки

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

Откройте .sln-файл в Visual Studio. Запустите приложение.

Следуйте инструкциям в разделе Тестирование WebApp1

Создание библиотеки RCL

В этом разделе создается библиотека RCL. Файлы Razor будут добавлены в RCL.

Создание проекта RCL:

  • В Visual Studio в меню Файл щелкните Создать > Проект.
  • Выберите Новое веб-приложение ASP.NET Core.
  • Присвойте приложению имя RazorUIClassLib > ОК.
  • Убедитесь, что выбрано ASP.NET Core 2.1 или более поздней версии.
  • Выберите Библиотека классов Razor > ОК.
  • Добавьте файл частичного представления Razor с именем RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml.

Добавление файлов и папок Razor в проект

  • Замените разметку в RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml следующим кодом:

    <h3>_Message.cshtml partial view.</h3>
    
    <p>RazorUIClassLib\Areas\MyFeature\Pages\Shared\_Message.cshtml</p>
    
  • Замените разметку в RazorUIClassLib/Areas/MyFeature/Pages/Page1.cshtml следующим кодом:

    @page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    
    <h2>Hello from a Razor UI class library!</h2>
    <p> From  RazorUIClassLib\Areas\MyFeature\Pages\Page1.cshtml</p>
    
    <partial name="_Message" />
    

    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers требуется для использования частичного представления (<partial name="_Message" />). Вместо включения директивы @addTagHelper можно добавить файл _ViewImports.cshtml. Пример.

    dotnet new viewimports -o RazorUIClassLib/Areas/MyFeature/Pages
    

    Дополнительные сведения о _ViewImports.cshtml см. в разделе Импорт общих директив.

  • Создайте библиотеку классов, чтобы убедиться в отсутствии ошибок компилятора:

    dotnet build RazorUIClassLib
    

Выходные данные сборки содержат RazorUIClassLib.dll и RazorUIClassLib.Views.dll. RazorUIClassLib.Views.dll содержит скомпилированное содержимое Razor.

Использование библиотеки пользовательского интерфейса Razor в проекте Razor Pages

Создание веб-приложения Razor Pages:

  • В обозревателе решений щелкните решение правой кнопкой мыши и выберите Добавить > Новый проект.

  • Выберите Новое веб-приложение ASP.NET Core.

  • Назовите приложение WebApp1.

  • Убедитесь, что выбрано ASP.NET Core 2.1 или более поздней версии.

  • Выберите Веб-приложение > ОК.

  • В обозревателе решений щелкните правой кнопкой мыши WebApp1 и выберите Назначить запускаемым проектом.

  • В обозревателе решений щелкните правой кнопкой мыши WebApp1 и выберите Зависимости сборки > Зависимости проекта.

  • Отметьте RazorUIClassLib как зависимость от WebApp1.

  • В обозревателе решений щелкните правой кнопкой мыши WebApp1 и выберите Добавить > Ссылка.

  • В диалоговом окне Диспетчер ссылок нажмите RazorUIClassLib > ОК.

Запустите приложение.

Тестирование WebApp1

Перейдите по адресу /MyFeature/Page1, чтобы убедиться в том, что используется библиотека классов пользовательского интерфейса Razor.

Переопределение представлений, частичных представлений и страниц

При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении. Например, если вы добавите WebApp1/Areas/MyFeature/Pages/Page1.cshtml в WebApp1, Page1 в WebApp1 будет иметь приоритет над Page1 в RCL.

В примере загрузки переименуйте WebApp1/Areas/MyFeature2 в WebApp1/Areas/MyFeature, чтобы задать приоритет теста.

Скопируйте частичное представление RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml в WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Обновите разметку, чтобы указать новое расположение. Скомпилируйте и запустите приложение, чтобы убедиться, что используется версия частичного представления из приложения.

Макет страниц RCL

Чтобы ссылаться на содержимое RCL так, как будто оно находится в папке Pages веб-приложения, создайте проект RCL со следующей структурой файлов:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Предположим, что RazorUIClassLib/Pages/Shared содержит два частичных файла: _Header.cshtml и _Footer.cshtml. В файл _Layout.cshtml можно добавить теги <partial>:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

В библиотеку классов Razor (RCL) можно встроить представления Razor, страницы, контроллеры, модели страниц, компоненты Razor, компоненты представления. RCL можно упаковать и использовать повторно. Приложения могут включать RCL и переопределять содержащиеся в нем представления и страницы. При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении.

Просмотреть или скачать образец кода (как скачивать)

Создание библиотеки классов с пользовательским интерфейсом Razor

  • В Visual Studio выберите Создать проект.
  • Выберите Библиотека классов Razor > Далее.
  • Назовите библиотеку (например, "RazorClassLib") и нажмите кнопку Создать. Чтобы избежать конфликта имени файла с созданной библиотекой представлений, проверьте, что имя библиотеки не заканчивается на .Views.
  • Если должны поддерживаться представления, установите флажок Представления и страницы поддержки. По умолчанию поддерживаются только страницы Razor Pages. Выберите Создать.

По умолчанию для шаблона библиотеки классов Razor (RCL) используется разработка компонентов Razor. При выборе параметра Представления и страницы поддержки поддерживаются страницы и представления.

Добавьте файлы Razor в библиотеку RCL.

В шаблонах ASP.NET Core предполагается, что содержимое RCL находится в папке Areas. Сведения о том, как создать библиотеку RCL с содержимым в папке ~/Pages, а не ~/Areas/Pages, см. в разделе Макет страниц RCL ниже.

Ссылка на содержимое RCL

На RCL могут ссылаться:

Переопределение представлений, частичных представлений и страниц

При обнаружении представления, частичного представления или страницы Razor и в веб-приложении, и в RCL приоритет имеет разметка Razor (файл .cshtml) в веб-приложении. Например, если вы добавите WebApp1/Areas/MyFeature/Pages/Page1.cshtml в WebApp1, Page1 в WebApp1 будет иметь приоритет над Page1 в RCL.

В примере загрузки переименуйте WebApp1/Areas/MyFeature2 в WebApp1/Areas/MyFeature, чтобы задать приоритет теста.

Скопируйте частичное представление RazorUIClassLib/Areas/MyFeature/Pages/Shared/_Message.cshtml в WebApp1/Areas/MyFeature/Pages/Shared/_Message.cshtml. Обновите разметку, чтобы указать новое расположение. Скомпилируйте и запустите приложение, чтобы убедиться, что используется версия частичного представления из приложения.

Если RCL использует Razor Pages, включите службы Razor Pages и конечные точки в ведущем приложении:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        endpoints.MapRazorPages();
    });
}

Макет страниц RCL

Чтобы ссылаться на содержимое RCL так, как будто оно находится в папке Pages веб-приложения, создайте проект RCL со следующей структурой файлов:

  • RazorUIClassLib/Pages
  • RazorUIClassLib/Pages/Shared

Предположим, что RazorUIClassLib/Pages/Shared содержит два частичных файла: _Header.cshtml и _Footer.cshtml. В файл _Layout.cshtml можно добавить теги <partial>:

<body>
  <partial name="_Header">
  @RenderBody()
  <partial name="_Footer">
</body>

Добавьте файл _ViewStart.cshtml в папку Pages проекта RCL, чтобы использовать файл _Layout.cshtml из ведущего веб-приложения:

@{
    Layout = "_Layout";
}

Создание библиотеки RCL со статическими ресурсами

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

Чтобы включить сопутствующие ресурсы в библиотеку RCL, создайте папку wwwroot в библиотеке классов и добавьте в нее все необходимые файлы.

При упаковке RCL все сопутствующие ресурсы в папке wwwroot автоматически включаются в пакет.

Используйте команду dotnet pack, а не NuGet.exe версии nuget pack.

Исключение статических ресурсов

Чтобы исключить статические ресурсы, добавьте путь исключения в группу свойств $(DefaultItemExcludes) в файле проекта. Записи следует разделять точкой с запятой (;).

В следующем примере таблица стилей lib.css в папкеwwwroot не считается статическим ресурсом и не включается в опубликованную библиотеку RCL:

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemExcludes);wwwroot\lib.css</DefaultItemExcludes>
</PropertyGroup>

Интеграция с TypeScript

Чтобы включить файлы TypeScript в библиотеку RCL, выполните указанные ниже действия.

  1. Поместите файлы TypeScript (.ts) в папку, отличную от wwwroot. Например, их можно поместить в папку Client.

  2. Укажите папку wwwroot в качестве выходного пути сборки TypeScript. Задайте свойство TypescriptOutDir в группе PropertyGroup в файле проекта:

    <TypescriptOutDir>wwwroot</TypescriptOutDir>
    
  3. Включите целевой объект TypeScript в качестве зависимости целевого объекта ResolveCurrentProjectStaticWebAssets, добавив следующий целевой объект в группу PropertyGroup в файле проекта:

    <ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
      CompileTypeScript;
      $(ResolveCurrentProjectStaticWebAssetsInputs)
    </ResolveCurrentProjectStaticWebAssetsInputsDependsOn>
    

Использование содержимого из связанной библиотеки RCL

Файлы в папке wwwroot библиотеки RCL доступны самой библиотеке RCL или использующему ее приложению по пути _content/{PACKAGE ID}/. Например, библиотека с именем сборки Razor.Class.Lib и без указания <PackageId> в файле проекта приводит к указанию пути к статическому содержимому в _content/Razor.Class.Lib/. При создании пакета NuGet имя сборки не совпадает с идентификатором пакета (<PackageId> в файле проекта библиотеки), используйте идентификатор пакета, как указано в файле проекта для {PACKAGE ID}.

Использующее библиотеку приложение ссылается на предоставляемые ею статические ресурсы с помощью тегов HTML <script>, <style>, <img> и других. Для приложения необходимо включить поддержку статических файлов в Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    app.UseStaticFiles();

    ...
}

Когда приложение запускается из выходного пути сборки (dotnet run), в среде разработки статические веб-ресурсы включены по умолчанию. Для поддержки ресурсов в других средах при запуске из выходного пути сборки вызовите метод UseStaticWebAssets построителя узла в файле Program.cs:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStaticWebAssets();
                webBuilder.UseStartup<Startup>();
            });
}

При запуске приложения из пути публикации (dotnet publish) вызывать UseStaticWebAssets не нужно.

Процесс разработки нескольких проектов

При запуске использующего библиотеку приложения происходит следующее:

  • Ресурсы RCL остаются в исходных папках. Они не перемещаются в приложение.
  • Любые изменения в папке wwwroot библиотеки RCL отражаются в приложении после перестроения RCL, причем приложение перестраивать не требуется.

При сборке библиотеки RCL создается манифест, в котором описывается расположение статических веб-ресурсов. Использующее библиотеку приложение считывает манифест во время выполнения для получения ресурсов из связанных проектов и пакетов. При добавлении нового ресурса в библиотеку RCL ее необходимо перестроить, чтобы обновить манифест. Только после этого приложение сможет получить доступ к новому ресурсу.

Публикация

При публикации приложения сопутствующие ресурсы из всех связанных проектов и пакетов копируются в папку wwwroot опубликованного приложения в папке _content/{PACKAGE ID}/. При создании пакета NuGet имя сборки не совпадает с идентификатором пакета (<PackageId> в файле проекта библиотеки), используйте идентификатор пакета, указанный в файле проекта для {PACKAGE ID} при проверке папки wwwroot для опубликованных ресурсов.

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