Использование интерфейсов API ASP.NET Core в библиотеке классов

Автор: Скотт Адди (Scott Addie)

В этом документе приводятся рекомендации по использованию интерфейсов API ASP.NET Core в библиотеке классов. Остальные рекомендации по работе с библиотекой см. в статье Руководство по библиотекам с открытым кодом.

Определение поддерживаемых версий ASP.NET Core

ASP.NET Core соответствует политике поддержки .NET Core. Ознакомьтесь с политикой поддержки, чтобы узнать, какие версии ASP.NET Core поддерживаются в библиотеке. Библиотека должна:

  • по возможности предоставлять поддержку всех версий ASP.NET Core, классифицированную как долгосрочная поддержка (LTS).
  • не обязательно предоставлять поддержку версий ASP.NET Core, классифицированную как окончание жизненного цикла (EOL).

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

Использование общей платформы .NET Core

В выпуске .NET Core версии 3.0 многие сборки ASP.NET Core больше не публикуются в NuGet в качестве пакетов. Вместо этого сборки включаются в состав общей платформы Microsoft.AspNetCore.App, которая устанавливается вместе с пакетом SDK для .NET Core и установщиками среды выполнения. Список пакетов, которые больше не публикуются, см. в разделе Remove obsolete package references (Удаление устаревших ссылок на пакеты).

Начиная с .NET Core версии 3.0, проекты, использующие пакет SDK Microsoft.NET.Sdk.Web для MSBuild, неявно ссылаются на общую платформу. Проекты, использующие пакет SDK для Microsoft.NET.Sdk или Microsoft.NET.Sdk.Razor, должны ссылаться на ASP.NET Core, чтобы использовать интерфейсы API ASP.NET Core в общей платформе.

Чтобы сослаться на ASP.NET Core, добавьте в файл проекта следующий элемент <FrameworkReference>:

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

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

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

</Project>

Включение расширяемости Blazor

Blazor поддерживает создание Razor библиотек классов компонентов для серверных и клиентских приложений. Для поддержки Razor компонентов в библиотеке классов библиотека классов должна использовать Microsoft.NET.Sdk.Razor ПАКЕТ SDK.

Поддержка серверных и клиентских приложений

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

Используйте шаблон проекта библиотеки классов Razor.

Примечание.

Не устанавливайте флажок представления. Выбор проверка box приводит к тому, что библиотека классов поддерживает только серверные приложения.

Библиотека, созданная на основе шаблона проекта:

  • предназначена для текущей платформы .NET Framework на основе установленного пакета SDK;
  • включает в браузере проверки на совместимость для зависимостей платформы, добавляя browser в качестве поддерживаемой платформы с элементом MSBuild SupportedPlatform.
  • добавляет ссылку на пакет NuGet для Microsoft.AspNetCore.Components.Web.

RazorClassLibrary-CSharp.csproj (справочный источник)

Примечание.

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

Поддержка нескольких версий платформы

Если библиотека должна поддерживать функции, добавленные в Blazor в текущем выпуске, и при этом поддерживать один или несколько более ранних выпусков, настройте ее для нацеливания на несколько версий. Укажите разделенный точками с запятой список моникеров целевой платформы (TFM) в свойстве MSBuild TargetFrameworks:

<TargetFrameworks>{TARGET FRAMEWORKS}</TargetFrameworks>

В предыдущем примере {TARGET FRAMEWORKS} заполнитель представляет список TFM с запятой. Например, netcoreapp3.1;net5.0.

Поддержка только потребления на стороне сервера

Библиотеки классов редко создаются только для поддержки серверных приложений. Если для библиотеки классов требуются только серверные функции, такие как доступ или CircuitHandlerMicrosoft.AspNetCore.Components.Server.ProtectedBrowserStorageиспользование ASP.NET основных функций, таких как по промежуточному слоям, контроллерам MVC или Razor Pages, используйте один из следующих подходов:

  • Укажите, что библиотека поддерживает страницы и представления при создании библиотеки со страницами поддержки и представлениями проверка box (Visual Studio) или -s|--support-pages-and-views параметром с dotnet new помощью команды:

    dotnet new razorclasslib -s
    
  • В файле проекта библиотеки предоставляется ссылка только на платформу ASP.NET Core в файле проекта библиотеки, а также любые другие необходимые свойства MSBuild:

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

Дополнительные сведения о библиотеках, содержащих компоненты Razor, см. в статье Использование компонентов Razor ASP.NET Core из библиотеки классов Razor (RCL).

Включение расширяемости MVC

В этом разделе приведены рекомендации по библиотекам, включая:

В этом разделе не рассматривается настройка различных версий для поддержки нескольких версий MVC. Рекомендации по поддержке нескольких версий ASP.NET Core см. в разделе Support multiple ASP.NET Core versions (Поддержка нескольких ASP.NET Core версий).

Представления Razor или Razor Pages

Проект, включающий Razor представления или Razor страницы , должен использовать Microsoft.NET.Sdk.Razor ПАКЕТ SDK.

Если проект предназначен для .NET Core 3.x, для него требуется:

  • Для свойства MSBuild AddRazorSupportForMvc задать значение true.
  • Элемент <FrameworkReference> для общей платформы.

Шаблон Razor проекта библиотеки классов удовлетворяет приведенным выше требованиям для проектов, предназначенных для .NET Core. Для редактора следует использовать следующие инструкции.

Используйте шаблон проекта библиотеки классов Razor. Установите флажок Support pages and views (Представления и страницы поддержки).

Например:

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

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

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

</Project>

Если проект предназначен для .NET Standard, требуется ссылка на пакет Microsoft.AspNetCore.Mvc. Пакет Microsoft.AspNetCore.Mvc перемещен в общую платформу ASP.NET Core 3.0 и поэтому больше не публикуется. Например:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
  </ItemGroup>

</Project>

Вспомогательные функции тегов

Проект, содержащий вспомогательные функции тегов должен использовать пакет SDK для Microsoft.NET.Sdk. При использовании .NET Core 3.x добавьте элемент <FrameworkReference> для общей платформы. Например:

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

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

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

</Project>

Если используется .NET Standard (для поддержки версий, предшествующих ASP.NET Core 3.x), добавьте ссылку на пакет Microsoft.AspNetCore.Mvc.Razor. Пакет Microsoft.AspNetCore.Mvc.Razor перемещен в общую платформу и поэтому больше не публикуется. Например:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
  </ItemGroup>

</Project>

Компоненты представлений

Проект, содержащий вспомогательные функции тегов, должен использовать пакет SDK для Microsoft.NET.Sdk. При использовании .NET Core 3.x добавьте элемент <FrameworkReference> для общей платформы. Например:

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

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

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

</Project>

Если используется .NET Standard (для поддержки версий, предшествующих ASP.NET Core 3.x), добавьте ссылку на пакет Microsoft.AspNetCore.Mvc.ViewFeatures. Пакет Microsoft.AspNetCore.Mvc.ViewFeatures перемещен в общую платформу и поэтому больше не публикуется. Например:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.2.0" />
  </ItemGroup>

</Project>

Поддержка нескольких версий ASP.NET Core

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

  • ASP.NET Core 2.1 для платформы .NET Framework 4.6.1;
  • ASP.NET Core 2.x для платформы .NET Framework 2.x;
  • ASP.NET Core 3.x для платформы .NET Framework 3.x.

Следующий файл проекта поддерживает эти варианты с помощью свойства TargetFrameworks:

<Project Sdk="Microsoft.NET.Sdk">
  
  <PropertyGroup>
    <TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net461</TargetFrameworks>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="Markdig" Version="0.16.0" />
  </ItemGroup>
  
  <ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>
</Project>

Для предыдущего файла проекта:

  • Для всех потребителей добавляется пакет Markdig.
  • Для потребителей, использующих .NET Framework 4.6.1 или более поздней версии или .NET Core 2.x, добавляется ссылка на Microsoft.AspNetCore.Mvc.Razor. Версия 2.1.0 пакета работает с ASP.NET Core 2.2 из-за обратной совместимости.
  • На общую платформу ссылаются потребители, использующие .NET Core 3.x. Пакет Microsoft.AspNetCore.Mvc.Razor включен в общую платформу.

Кроме того, можно использовать .NET Standard 2.0 вместо .NET Core 2.1 и .NET Framework 4.6.1:

<Project Sdk="Microsoft.NET.Sdk">
  
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="Markdig" Version="0.16.0" />
  </ItemGroup>
  
  <ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>
</Project>

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

  • Так как библиотека содержит только вспомогательные функции тегов, она проще для определенных платформ, на которых выполняется ASP.NET Core: .NET Core и .NET Framework. Вспомогательные функции тегов нельзя использовать с другими совместимыми с .NET Standard 2.0 целевыми платформами, такими как Unity, UWP и Xamarin.
  • Некоторые проблемы с использованием .NET Standard 2.0 в .NET Framework были устраненные в .NET Framework версии 4.7.2. Улучшить работу потребителей, использующих .NET Framework 4.6.1–4.7.1, можно, используя .NET Framework 4.6.1.

Если библиотека должна вызывать интерфейсы API для определенных платформ, вместо .NET Standard используйте конкретные реализации .NET. Дополнительные сведения см. в разделе Настройка для различных версий.

Использование API, который еще не изменился

Представьте, что вы обновляете библиотеку ПО промежуточного слоя с .NET Core версии 2.2–3.1. API-интерфейсы ASP.NET Core ПО промежуточного слоя, используемые в библиотеке, не изменились в версиях ASP.NET Core 2.2 и 3.1. Чтобы продолжить поддержку библиотеки ПО промежуточного слоя в .NET Core 3.1, выполните следующие действия.

  • Следуйте указаниям в руководстве по работе со стандартной библиотекой.
  • Добавьте ссылку на пакет для каждого пакета API-интерфейса NuGet, если соответствующая сборка отсутствует в общей платформе.

Использование измененного API

Представьте, что вы обновляете библиотеку с .NET Core версии 2.2 до 3.1. API-интерфейс ASP.NET Core, используемый в библиотеке, имеет критические изменения в ASP.NET Core 3.1. Определите, можно ли перезаписывать библиотеку, чтобы не использовать неработающий API во всех версиях.

Если вы можете переписать библиотеку, сделайте это и продолжайте использовать более раннюю целевую платформу (например, .NET Standard 2.0 или .NET Framework 4.6.1) со ссылками на пакеты.

Если вы не можете переписать библиотеку, выполните следующие действия.

  • Добавьте целевой объект для .NET Core 3.1.
  • Добавьте элемент <FrameworkReference> для общей платформы.
  • Используйте директиву препроцессора #if с соответствующим символом целевой платформы для условной компиляции кода.

Например, синхронные операции чтения и записи по потокам HTTP-запросов и ответов по умолчанию отключены по ASP.NET Core 3.1. По умолчанию ASP.NET Core 2.2 поддерживает синхронное поведение. Рассмотрим библиотеку ПО промежуточного слоя, в которой должны быть включены синхронные операции чтения и записи, когда происходит операция ввода-вывода. Библиотека должна содержать код для включения синхронных функций в соответствующей директиве препроцессора. Например:

public async Task Invoke(HttpContext httpContext)
{
    if (httpContext.Request.Path.StartsWithSegments(_path, StringComparison.Ordinal))
    {
        httpContext.Response.StatusCode = (int) HttpStatusCode.OK;
        httpContext.Response.ContentType = "application/json";
        httpContext.Response.ContentLength = _bufferSize;

#if !NETCOREAPP3_1 && !NETCOREAPP5_0
        var syncIOFeature = httpContext.Features.Get<IHttpBodyControlFeature>();
        if (syncIOFeature != null)
        {
            syncIOFeature.AllowSynchronousIO = true;
        }

        using (var sw = new StreamWriter(
            httpContext.Response.Body, _encoding, bufferSize: _bufferSize))
        {
            _json.Serialize(sw, new JsonMessage { message = "Hello, World!" });
        }
#else
        await JsonSerializer.SerializeAsync<JsonMessage>(
            httpContext.Response.Body, new JsonMessage { message = "Hello, World!" });
#endif
        return;
    }

    await _next(httpContext);
}

Использование API, представленного в версии 3.1

Представьте, что вы хотите использовать API-интерфейс ASP.NET Core, который появился в ASP.NET Core 3.1. Оцените следующие вопросы.

  1. Работает ли в библиотеке новый API?
  2. Может ли библиотека реализовать эту функцию другим способом?

Если для работы библиотеки требуется API и нет способа реализовать его на уровне ниже:

  • Используйте только .NET Core 3.x.
  • Добавьте элемент <FrameworkReference> для общей платформы.

Если библиотека может реализовать эту функцию другим способом:

  • Добавьте .NET Core 3.x в качестве целевой платформы.
  • Добавьте элемент <FrameworkReference> для общей платформы.
  • Используйте директиву препроцессора #if с соответствующим символом целевой платформы для условной компиляции кода.

Например, следующая вспомогательная функция тега использует интерфейс IWebHostEnvironment, представленный в ASP.NET Core 3.1. Потребители, использующие .NET Core 3.1, выполняют путь кода, определенный символом NETCOREAPP3_1 целевой платформы. Тип параметра конструктора вспомогательной функции тега изменяется на IHostingEnvironment для потребителей .NET Core 2.1 и .NET Framework 4.6.1. Это изменение было необходимо, так как в ASP.NET Core 3.1 свойство IHostingEnvironment помечено как устаревшее и в качестве замены рекомендуется использовать IWebHostEnvironment.

[HtmlTargetElement("script", Attributes = "asp-inline")]
public class ScriptInliningTagHelper : TagHelper
{
    private readonly IFileProvider _wwwroot;

#if NETCOREAPP3_1
    public ScriptInliningTagHelper(IWebHostEnvironment env)
#else
    public ScriptInliningTagHelper(IHostingEnvironment env)
#endif
    {
        _wwwroot = env.WebRootFileProvider;
    }

    // code omitted for brevity
}

Следующий файл проекта с несколькими целевыми файлами поддерживает этот сценарий вспомогательной функции тега:

<Project Sdk="Microsoft.NET.Sdk">
  
  <PropertyGroup>
    <TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net461</TargetFrameworks>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="Markdig" Version="0.16.0" />
  </ItemGroup>
  
  <ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>
</Project>

Использование API, удаленного из общей платформы

Чтобы использовать сборку ASP.NET Core, которая была удалена из общей платформы, добавьте соответствующую ссылку на пакет. Список пакетов, удаленных из общей платформы в ASP.NET Core 3.1, см. в разделе Remove obsolete package references (Удаление устаревших ссылок на пакеты).

Например, чтобы добавить клиент веб-API:

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

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

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

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
  </ItemGroup>

</Project>

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