Usar APIs do ASP.NET Core em uma biblioteca de classes

Por Scott Addie

Este documento fornece diretrizes para o uso de APIs do ASP.NET Core em uma biblioteca de classes. Para obter todas as outras diretrizes de biblioteca, confira Diretrizes de biblioteca de software livre.

Determinar a quais versões do ASP.NET Core dar suporte

O ASP.NET Core adere à política de suporte do .NET Core. Confira a política de suporte para determinar a quais versões do ASP.NET Core dar suporte em uma biblioteca. Uma biblioteca deve:

  • Fazer um esforço para dar suporte a todas as versões do ASP.NET Core classificadas como LTS (Suporte de Longo Prazo).
  • Não se sentir obrigada a dar suporte a versões do ASP.NET Core classificadas como EOL (End of Life).

À medida que as versões prévias do ASP.NET Core são disponibilizadas, as alterações significativas são postadas no repositório GitHub aspnet/Announcements. O teste de compatibilidade de bibliotecas pode ser realizado à medida que os recursos da estrutura vão sendo desenvolvidos.

Usar a estrutura compartilhada do ASP.NET Core

Com o lançamento do .NET Core 3.0, muitos assemblies do ASP.NET Core não são mais publicados no NuGet como pacotes. Os assemblies agora são incluídos na estrutura compartilhada Microsoft.AspNetCore.App, que é instalada com o SDK do .NET Core e instaladores de runtime. Para obter uma lista de pacotes que não estão mais sendo publicados, confira Remover referências de pacote obsoletas.

A partir do .NET Core 3.0, projetos que usam o SDK do MSBuild Microsoft.NET.Sdk.Web referenciam implicitamente a estrutura compartilhada. Os projetos que usam o SDK do Microsoft.NET.Sdk ou Microsoft.NET.Sdk.Razor precisam fazer referência ao ASP.NET Core para usar APIs do ASP.NET Core na estrutura compartilhada.

Para fazer referência ao ASP.NET Core, adicione o seguinte elemento <FrameworkReference> ao arquivo de projeto:

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

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

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

</Project>

Incluir extensibilidade do Blazor

O Blazor dá suporte à criação de bibliotecas de classes de componentes Razor para aplicativos do servidor e do lado do cliente. Para dar suporte aos componentes Razor em uma biblioteca de classes, a biblioteca de classes precisa usar o SDK Microsoft.NET.Sdk.Razor.

Dar suporte a aplicativos do servidor e do lado do cliente

Para dar suporte ao consumo de componentes Razor por aplicativos do servidor e do lado do cliente por meio de uma só biblioteca, use as instruções a seguir para seu editor.

Use o modelo de projeto Biblioteca de Classes do Razor.

Observação

Não marque a caixa de seleção Páginas de suporte e exibições. Se você marcar a caixa de seleção, o resultado será uma biblioteca de classes que só dá suporte a aplicativos do servidor.

A biblioteca gerada com base no modelo de projeto:

  • Direciona o .NET Framework atual com base no SDK instalado.
  • Habilita as verificações de compatibilidade do navegador em relação a dependências de plataforma, incluindo browser como plataforma com suporte com o item de MSBuild SupportedPlatform.
  • Adiciona uma referência de pacote NuGet para Microsoft.AspNetCore.Components.Web.

RazorClassLibrary-CSharp.csproj (fonte de referência)

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Suporte a várias versões de estrutura

Se a biblioteca precisar dar suporte aos recursos adicionados ao Blazor na versão atual e, ao mesmo tempo, dar suporte a uma ou mais versões anteriores, multissegmente a biblioteca. Forneça uma lista separada por ponto e vírgula de TFMs (Monikers da Estrutura de Destino) na propriedade MSBuild TargetFrameworks:

<TargetFrameworks>{TARGET FRAMEWORKS}</TargetFrameworks>

No exemplo anterior, o espaço reservado {TARGET FRAMEWORKS} representa a lista de TFMs separadas por ponto e vírgula. Por exemplo, netcoreapp3.1;net5.0.

Dar suporte apenas ao consumo do servidor

As bibliotecas de classes raramente são criadas para dar suporte apenas a aplicativos do servidor. Se a biblioteca de classes só exigir recursos específicos do servidor, como acesso a CircuitHandler ou Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage, ou o uso de recursos específicos do ASP.NET Core, como middleware, controladores MVC ou Razor Pages, use uma das seguintes abordagens:

  • Especifique que a biblioteca dá suporte a páginas e exibições quando ela é criada com a caixa de seleção Dar suporte a páginas e exibições (Visual Studio) ou com a opção -s|--support-pages-and-views usando o comando dotnet new:

    dotnet new razorclasslib -s
    
  • Forneça apenas uma referência de estrutura ao ASP.NET Core no arquivo de projeto da biblioteca, além das outras propriedades obrigatórias do MSBuild:

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

Para obter mais informações sobre bibliotecas que contêm componentes Razor, confira Consumir componentes Razor do ASP.NET Core de uma biblioteca de classes Razor (RCL).

Incluir extensibilidade do MVC

Esta seção descreve as recomendações para bibliotecas que incluem:

Esta seção não discute multissegmentação para dar suporte a várias versões do MVC. Para obter diretrizes sobre como dar suporte a várias versões do ASP.NET Core, confira Suporte a várias versões do ASP.NET Core.

Exibições Razor ou Razor Pages

Um projeto que inclui Razor exibições ou Razor Pages precisa usar o SDK Microsoft.NET.Sdk.Razor.

Se o projeto tiver como objetivo o .NET Core 3.x, ele exigirá:

  • Uma propriedade MSBuild AddRazorSupportForMvc definida como true.
  • Um elemento <FrameworkReference> para a estrutura compartilhada.

O modelo de projeto Biblioteca de classes do Razor atende aos requisitos anteriores para projetos com o .NET Core como objetivo. Use as instruções abaixo para o editor.

Use o modelo de projeto Biblioteca de Classes do Razor. A caixa de seleção Páginas de suporte e exibições do modelo devem ser selecionadas.

Por exemplo:

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

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

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

</Project>

Se o projeto tiver como objetivo o .NET Standard, será necessária uma referência de pacote Microsoft.AspNetCore.Mvc. O pacote Microsoft.AspNetCore.Mvc passou para a estrutura compartilhada no ASP.NET Core 3.0 e, portanto, não é mais publicado. Por exemplo:

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

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

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

</Project>

Auxiliares de Marca

Um projeto que inclui Auxiliares de Marcação deve usar o SDK do Microsoft.NET.Sdk. Se tiver como objetivo o .NET Core 3.x, adicione um elemento <FrameworkReference> para a estrutura compartilhada. Por exemplo:

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

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

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

</Project>

Se o objetivo for o .NET Standard (para dar suporte a versões anteriores ao ASP.NET Core 3.x), adicione uma referência de pacote ao Microsoft.AspNetCore.Mvc.Razor. O pacote Microsoft.AspNetCore.Mvc.Razor passou para a estrutura compartilhada e, portanto, não é mais publicado. Por exemplo:

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

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

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

</Project>

Componentes da exibição

Um projeto que inclui Componentes de exibição deve usar o SDK Microsoft.NET.Sdk. Se tiver como objetivo o .NET Core 3.x, adicione um elemento <FrameworkReference> para a estrutura compartilhada. Por exemplo:

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

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

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

</Project>

Se o objetivo for o .NET Standard (para dar suporte a versões anteriores ao ASP.NET Core 3.x), adicione uma referência de pacote a Microsoft.AspNetCore.Mvc.ViewFeatures. O pacote Microsoft.AspNetCore.Mvc.ViewFeatures passou para a estrutura compartilhada e, portanto, não é mais publicado. Por exemplo:

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

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

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

</Project>

Suporte a várias versões do ASP.NET Core

A multissegmentação é necessária para criar uma biblioteca que dê suporte a várias variantes do ASP.NET Core. Considere um cenário no qual uma biblioteca de Auxiliares de Marcação deve dar suporte às seguintes variantes do ASP.NET Core:

  • ASP.NET Core 2.1 visando o .NET Framework 4.6.1
  • ASP.NET Core 2.x visando o .NET Core 2.x
  • ASP.NET Core 3.x visando o .NET Core 3.x

O arquivo de projeto abaixo dá suporte a essas variantes por meio da propriedade 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>

Com o arquivo de projeto anterior:

  • O pacote Markdig é adicionado para todos os consumidores.
  • Uma referência a Microsoft.AspNetCore.Mvc.Razor é adicionada para consumidores que visam ao .NET Framework 4.6.1 ou posterior, ou ao .NET Core 2.x. A versão 2.1.0 do pacote funciona com o ASP.NET Core 2.2 devido à compatibilidade com versões anteriores.
  • A estrutura compartilhada é referenciada para consumidores que têm como objetivo o .NET Core 3.x. O pacote Microsoft.AspNetCore.Mvc.Razor está incluído na estrutura compartilhada.

Como alternativa, o .NET Standard 2.0 pode ser visado em vez do .NET Core 2.1 junto com o .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>

Com o arquivo de projeto anterior, existem as seguintes ressalvas:

  • Como a biblioteca contém apenas auxiliares de marcação, é mais simples visar as plataformas específicas nas quais o ASP.NET Core é executado: .NET Core e .NET Framework. Os Auxiliares de Marcação não podem ser usados por outras estruturas de destino compatíveis com o .NET Standard 2.0, como Unity, UWP e Xamarin.
  • Usar o .NET Standard 2.0 do .NET Framework tem alguns problemas que foram resolvidos no .NET Framework 4.7.2. Você pode melhorar a experiência para os consumidores que usam o .NET Framework 4.6.1 a 4.7.1 visando o .NET Framework 4.6.1.

Se sua biblioteca precisar chamar APIs específicas da plataforma, tenha como objetivo implementações específicas do .NET em vez do .NET Standard. Para obter mais informações, confira Multissegmentação.

Usar uma API que não foi alterada

Imagine um cenário no qual você está atualizando uma biblioteca de middleware do .NET Core 2.2 para o 3.1. As APIs de middleware do ASP.NET Core que estão sendo usadas na biblioteca não foram alteradas entre o ASP.NET Core 2.2 e o 3.1. Para continuar dando suporte à biblioteca de middleware no .NET Core 3.1, execute as seguintes etapas:

  • Siga as diretrizes de biblioteca padrão.
  • Adicione uma referência de pacote relativa ao pacote NuGet de cada API quando o assembly correspondente não existir na estrutura compartilhada.

Usar uma API que foi alterada

Imagine um cenário no qual você está atualizando uma biblioteca do .NET Core 2.2 para o .NET Core 3.1. Uma API do ASP.NET Core que está sendo usada na biblioteca tem uma alteração interruptiva no ASP.NET Core 3.1. Considere se a biblioteca pode ser reescrita para não usar a API interrompida em todas as versões.

Se você puder reescrever a biblioteca, faça isso e continue a ter como objetivo uma estrutura de destino anterior (por exemplo, .NET Standard 2.0 ou .NET Framework 4.6.1) com referências de pacote.

Se você não conseguir reescrever a biblioteca, execute as seguintes etapas:

  • Adicione um destino para o .NET Core 3.1.
  • Adicione um elemento <FrameworkReference> para a estrutura compartilhada.
  • Use a diretiva de pré-processador #if com o símbolo de estrutura de destino apropriado para compilar condicionalmente o código.

Por exemplo, leituras e gravações síncronas em fluxos de solicitação e resposta HTTP ficam desabilitadas por padrão a partir do ASP.NET Core 3.1. O ASP.NET Core 2.2 dá suporte ao comportamento síncrono por padrão. Considere uma biblioteca de middleware na qual as leituras e gravações síncronas devem ser habilitadas onde a E/S está ocorrendo. A biblioteca deve anexar o código para habilitar recursos síncronos na diretiva de pré-processador apropriada. Por exemplo:

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);
}

Usar uma API introduzida na versão 3.1

Imagine que você deseja usar uma API do ASP.NET Core que foi introduzida no ASP.NET Core 3.1. Considere as seguintes perguntas:

  1. A biblioteca exige a nova API para funcionar?
  2. A biblioteca pode implementar esse recurso de uma maneira diferente?

Se a biblioteca exigir funcionalmente a API e não houver como implementá-la no nível inferior:

  • Tenha como objetivo somente o .NET Core 3.x.
  • Adicione um elemento <FrameworkReference> para a estrutura compartilhada.

Se a biblioteca puder implementar o recurso de uma maneira diferente:

  • Adicione o .NET Core 3.x como uma estrutura de destino.
  • Adicione um elemento <FrameworkReference> para a estrutura compartilhada.
  • Use a diretiva de pré-processador #if com o símbolo de estrutura de destino apropriado para compilar condicionalmente o código.

Por exemplo, o Auxiliar de Marcação a seguir usa a interface IWebHostEnvironment introduzida no ASP.NET Core 3.1. Os consumidores que visam ao .NET Core 3.1 executam o caminho de código definido pelo símbolo da estrutura de destino NETCOREAPP3_1. O tipo de parâmetro do construtor do Auxiliar de Marcação muda para IHostingEnvironment no caso de consumidores do .NET Core 2.1 e do .NET Framework 4.6.1. Essa alteração foi necessária porque o ASP.NET Core 3.1 marcou IHostingEnvironment como obsoleto e recomendou IWebHostEnvironment como substituto.

[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
}

O seguinte arquivo de projeto de multissegmentação dá suporte a esse cenário de Auxiliar de Marcação:

<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>

Usar uma API removida da estrutura compartilhada

Para usar um assembly ASP.NET Core que foi removido da estrutura compartilhada, adicione a referência de pacote apropriada. Para obter uma lista de pacotes removidos da estrutura compartilhada no ASP.NET Core 3.1, confira Remover referências de pacote obsoletas.

Por exemplo, para adicionar o cliente da API Web:

<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>

Recursos adicionais