PackageReference em arquivos de projeto

As referências de pacote, usando <PackageReference> itens do MSBuild, especificam dependências do pacote NuGet diretamente nos arquivos do projeto, em vez de ter um arquivo separado packages.config . O uso de PackageReference não afeta outros aspectos do NuGet; por exemplo, as configurações em NuGet.Config arquivos (incluindo fontes de pacote) ainda são aplicadas conforme explicado nas configurações comuns do NuGet.

Com PackageReference, você também pode usar condições do MSBuild para escolher referências de pacote por estrutura de destino ou outros agrupamentos. Ele também proporciona um controle refinado sobre as dependências e o fluxo de conteúdo. (Para obter mais detalhes, veja Empacotamento e restauração do NuGet como destinos do MSBuild.)

Suporte do tipo de projeto

Por padrão, o PackageReference é usado para projetos do .NET Core, para projetos do .NET Standard e para projetos da UWP direcionados ao Windows 10 Build 15063 (Atualização para Criadores) e posterior, com exceção dos projetos da C ++ UWP. Os projetos do .NET Framework são compatíveis com o PackageReference, mas, no momento, contam com packages.config como padrão. Para usar PackageReference, migre as dependências de packages.config para o arquivo de projeto e remova packages.config.

Os aplicativos ASP.NET do .NET Framework completo incluem apenas suporte limitado para PackageReference. Não há suporte para tipos de projeto C++ e JavaScript.

Adicionar um PackageReference

Adicione uma dependência ao arquivo de projeto usando a seguinte sintaxe:

<ItemGroup>
    <!-- ... -->
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
    <!-- ... -->
</ItemGroup>

Controlar a versão de dependência

A convenção para especificar a versão de um pacote é a mesma que usar packages.config:

<ItemGroup>
    <!-- ... -->
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
    <!-- ... -->
</ItemGroup>

No exemplo acima, 3.6.0 significa qualquer versão que seja >=3.6.0 com preferência pela versão mais baixa, conforme descrito no controle de versão do pacote.

Usando PackageReference para um projeto sem dependências de pacote

Avançado: se você não tem pacotes instalados em um projeto (não tem PackageReferences no arquivo de projeto nem um arquivo packages.config), mas deseja que o projeto seja restaurado como o estilo PackageReference, você pode definir uma propriedade de projeto RestoreProjectStyle como PackageReference em seu arquivo de projeto.

<PropertyGroup>
    <!--- ... -->
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
    <!--- ... -->
</PropertyGroup>    

Isso poderá ser útil se você fizer referência a projetos que são do estilo PackageReference (projetos de estilo csproj ou SDK existentes). Isso permitirá que os pacotes aos quais esses projetos fazem referência sejam referenciados "transitivamente" pelo seu projeto.

PackageReference e fontes

Em projetos PackageReference, as versões de dependência transitiva são resolvidas no momento da restauração. Assim, em projetos PackageReference, todas as fontes precisam estar disponíveis para todas as restaurações.

Versões flutuantes

Versões flutuante são compatíveis com PackageReference:

<ItemGroup>
    <!-- ... -->
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.*" />
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0-beta.*" />
    <!-- ... -->
</ItemGroup>

Controlar ativos de dependência

Você pode estar usando uma dependência puramente como uma estrutura de desenvolvimento e pode não querer expor isso aos projetos que consumirão o pacote. Nesse cenário, você pode usar os metadados do PrivateAssets para controlar esse comportamento.

<ItemGroup>
    <!-- ... -->

    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
        <PrivateAssets>all</PrivateAssets>
    </PackageReference>

    <!-- ... -->
</ItemGroup>

As seguintes marcas de metadados controlam ativos de dependência:

Marca Descrição Valor padrão
IncludeAssets Esses ativos serão consumidos all
ExcludeAssets Esses ativos não serão consumidos nenhum
PrivateAssets Esses ativos serão consumidos, mas não fluem para o projeto pai contentfiles;analyzers;build

Os valores permitidos para essas marcas são os seguintes, com vários valores separados por ponto e vírgula, exceto com all e none, que devem aparecer sozinhos:

Valor Descrição
compilar Conteúdo da pasta lib e controles se seu projeto puder compilar em relação aos assemblies dentro da pasta
runtime Conteúdo da pasta lib e runtimes pasta e controles se esses assemblies forem copiados para o diretório de saída de compilação
contentFiles O conteúdo da pasta contentfiles
compilar .props e .targets na pasta build
buildMultitargeting (4.0).props e .targets , na buildMultitargeting pasta, para direcionamento entre estruturas
buildTransitive (5,0+).props e .targets na buildTransitive pasta, para ativos que fluem transitivamente para qualquer projeto de consumo. Confira a página de recursos.
analisadores Analisadores de .NET
nativa O conteúdo da pasta native
nenhum Nenhuma das opções acima é usada.
all Todas as anteriores (exceto none)
<ItemGroup>
    <!-- ... -->
    <!-- Everything except the content files will be consumed by the project -->
    <!-- Everything except content files and analyzers will flow to the parent project-->
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
        <IncludeAssets>all</IncludeAssets> <!-- Default is `all`, can be omitted-->
        <ExcludeAssets>contentFiles</ExcludeAssets>
        <PrivateAssets>contentFiles;analyzers</PrivateAssets>
    </PackageReference>
    <!-- ... -->
    <!-- Everything except the compile will be consumed by the project -->
    <!-- Everything except contentFiles will flow to the parent project-->
    <PackageReference Include="Contoso.Utility.SomeOtherUsefulStuff" Version="3.6.0">
        <ExcludeAssets>compile</ExcludeAssets>
        <PrivateAssets>contentFiles</PrivateAssets>
    </PackageReference>
    <!-- ... -->
</ItemGroup>

Observe que, como build não está incluído em PrivateAssets, destino e objetos fluirão para o projeto pai. Considere, por exemplo, que a referência acima é usada em um projeto que compila um pacote do NuGet chamado AppLogger. O AppLogger pode consumir os destinos e objetos de Contoso.Utility.UsefulStuff, bem como projetos que consomem AppLogger.

Observação

Quando developmentDependency é definido como true em um arquivo .nuspec, isso marca um pacote como uma dependência somente de desenvolvimento, o que impede que o pacote seja incluído como uma dependência em outros pacotes. Com PackageReference (NuGet 4.8+), esse sinalizador também significa que ele excluirá os recursos em tempo de compilação. Para obter mais informações, confira Suporte do DevelopmentDependency para PackageReference.

Adicionar uma condição de PackageReference

É possível usar uma condição para controlar se um pacote está incluído, em que as condições podem usar qualquer variável MSBuild ou uma variável definida no arquivo de destinos ou objetos. No entanto, no momento, somente a variável TargetFramework é compatível.

Por exemplo, digamos que seu destino é netstandard1.4 e net452, mas tem uma dependência que é aplicável somente para net452. Nesse caso, não é aconselhável ter um projeto netstandard1.4 que está consumindo seu pacote para adicionar essa dependência desnecessária. Para evitar isso, você deve especificar uma condição no PackageReference da seguinte maneira:

<ItemGroup>
    <!-- ... -->
    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" Condition="'$(TargetFramework)' == 'net452'" />
    <!-- ... -->
</ItemGroup>

Um pacote compilado usando este projeto mostrará que Newtonsoft.Json está incluído como uma dependência somente para um destino net452:

O resultado da aplicação de uma condição em PackageReference com o VS2017

As condições também podem ser aplicadas no nível de ItemGroup e serão aplicadas a todos os elementos PackageReference filhos:

<ItemGroup Condition = "'$(TargetFramework)' == 'net452'">
    <!-- ... -->
    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
    <PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
    <!-- ... -->
</ItemGroup>

GeneratePathProperty

Esse recurso está disponível com o NuGet 5.0 ou superior e com o Visual Studio 2019 16.0 ou superior.

Às vezes, é desejável referenciar arquivos em um pacote de um destino do MSBuild. Em packages.config projetos baseados, os pacotes são instalados em uma pasta em relação ao arquivo de projeto. No entanto, em PackageReference, os pacotes são consumidos da pasta de pacotes globais , que pode variar de computador para computador.

Para preencher essa lacuna, o NuGet introduziu uma propriedade que aponta para o local do qual o pacote será consumido.

Exemplo:

  <ItemGroup>
      <PackageReference Include="Some.Package" Version="1.0.0" GeneratePathProperty="true" />
  </ItemGroup>

  <Target Name="TakeAction" AfterTargets="Build">
    <Exec Command="$(PkgSome_Package)\something.exe" />
  </Target>

Além disso, o NuGet gerará automaticamente propriedades para pacotes que contêm uma pasta de ferramentas.

  <ItemGroup>
      <PackageReference Include="Package.With.Tools" Version="1.0.0" />
  </ItemGroup>

  <Target Name="TakeAction" AfterTargets="Build">
    <Exec Command="$(PkgPackage_With_Tools)\tools\tool.exe" />
  </Target>

As propriedades e as identidades de pacote do MSBuild não têm as mesmas restrições, portanto, a identidade do pacote precisa ser alterada para um nome amigável do MSBuild, prefixado pela palavra Pkg. Para verificar o nome exato da propriedade gerada, examine o arquivo nuget.g.props gerado.

PackageReference Aliases

Em algumas instâncias raras, pacotes diferentes conterão classes no mesmo namespace. A partir do NuGet 5.7 & Visual Studio 2019 Atualização 7, equivalente ao ProjectReference, o PackageReference dá Aliasessuporte. Por padrão, nenhum aliases é fornecido. Quando um alias é especificado, todos os assemblies provenientes do pacote anotado precisam ser referenciados com um alias.

Você pode examinar o uso de exemplo no NuGet\Samples

No arquivo de projeto, especifique os aliases da seguinte maneira:

  <ItemGroup>
    <PackageReference Include="NuGet.Versioning" Version="5.8.0" Aliases="ExampleAlias" />
  </ItemGroup>

e, no código, use-o da seguinte maneira:

extern alias ExampleAlias;

namespace PackageReferenceAliasesExample
{
...
        {
            var version = ExampleAlias.NuGet.Versioning.NuGetVersion.Parse("5.0.0");
            Console.WriteLine($"Version : {version}");
        }
...
}

Avisos e erros do NuGet

Esse recurso está disponível com o NuGet 4.3 ou superior e com o Visual Studio 2017 15.3 ou superior.

Para muitos cenários de pacote e restauração, todos os avisos e erros do NuGet são codificados e começam com NU****. Todos os avisos e erros do NuGet estão listados na documentação de referência .

O NuGet observa as seguintes propriedades de aviso:

  • TreatWarningsAsErrors, trate todos os avisos como erros
  • WarningsAsErrors, trate avisos específicos como erros
  • NoWarn, oculte avisos específicos, em todo o projeto ou em todo o pacote.

Exemplos:

<PropertyGroup>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
    <WarningsAsErrors>$(WarningsAsErrors);NU1603;NU1605</WarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
    <NoWarn>$(NoWarn);NU5124</NoWarn>
</PropertyGroup>
...
<ItemGroup>
    <PackageReference Include="Contoso.Package" Version="1.0.0" NoWarn="NU1605" />
</ItemGroup>

Suprimindo avisos do NuGet

Embora seja recomendável que você resolva todos os avisos do NuGet durante suas operações de pacote e restauração, em determinadas situações, suprimi-los é garantido. Para suprimir um projeto de aviso em todo o projeto, considere fazer:

<PropertyGroup>
    <PackageVersion>5.0.0</PackageVersion>
    <NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
    <PackageReference Include="Contoso.Package" Version="1.0.0-beta.1"/>
</ItemGroup>

Às vezes, os avisos se aplicam apenas a um determinado pacote no grafo. Podemos optar por suprimir esse aviso de forma mais seletiva adicionando um NoWarn item PackageReference.

<PropertyGroup>
    <PackageVersion>5.0.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
    <PackageReference Include="Contoso.Package" Version="1.0.0-beta.1" NoWarn="NU1603" />
</ItemGroup>

Suprimindo avisos do pacote NuGet no Visual Studio

Quando estiver no Visual Studio, você também pode suprimir avisos por meio do IDE.

Bloqueio de dependências

Esse recurso está disponível no NuGet 4.9 ou superior e no Visual Studio 2017 15.9 ou superior.

A entrada para restauração do NuGet é um conjunto de PackageReference itens do arquivo de projeto (dependências diretas ou de nível superior) e a saída é um fechamento completo de todas as dependências do pacote, incluindo dependências transitivas. Se a lista PackageReference de entrada não tiver sido alterada, o NuGet tenta sempre produzir o mesmo fechamento completo das dependências de pacotes. No entanto, em alguns cenários, isso não poderá ser feito. Por exemplo:

  • Quando você usa versões flutuantes como <PackageReference Include="My.Sample.Lib" Version="4.*"/>. Embora a intenção aqui seja derivar para a versão mais recente sempre que uma restauração de pacotes ocorrer, há cenários em que os usuários exigem que o grafo seja bloqueado em uma determinada versão mais recente e derive para uma versão posterior, se disponível, mediante um gesto explícito.

  • Uma versão mais recente do pacote que corresponde aos requisitos de versão do PackageReference é publicada. Por ex.:

    • Dia 1: se você tiver especificado <PackageReference Include="My.Sample.Lib" Version="4.0.0"/>, mas as versões disponíveis nos repositórios do NuGet forem 4.1.0, 4.2.0 e 4.3.0. Nesse caso, o NuGet teria resolvido para 4.1.0 (versão mínima mais próxima)

    • Dia 2: a versão 4.0.0 é publicada. O NuGet agora encontrará a correspondência exata e iniciará a resolução como 4.0.0

  • Uma determinada versão de pacote é removida do repositório. Embora nuget.org não permita exclusões de pacote, nem todos os repositórios de pacote têm essa restrição. Isso faz com que o NuGet encontre a melhor correspondência quando não puder resolver a versão excluída.

Habilitando o arquivo de bloqueio

Para persistir o fechamento completo das dependências de pacotes, você pode optar pelo recurso de bloqueio de arquivos definindo a propriedade RestorePackagesWithLockFile do MSBuild para seu projeto:

<PropertyGroup>
    <!--- ... -->
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
    <!--- ... -->
</PropertyGroup>    

Se essa propriedade for definida, a restauração do NuGet gerará um arquivo de bloqueio – arquivo packages.lock.json no diretório raiz do projeto que lista todas as dependências do pacote.

Observação

Se um projeto tiver o arquivo packages.lock.json no diretório raiz, o arquivo de bloqueio sempre será usado com a restauração, mesmo que a propriedade RestorePackagesWithLockFile não esteja definida. Portanto, outra maneira de optar por esse recurso é através da criação um arquivo packages.lock.json fictício em branco no diretório raiz do projeto.

Comportamento restore com o arquivo de bloqueio

Se houver um arquivo de bloqueio para o projeto, o NuGet usará esse arquivo de bloqueio para executar restore. O NuGet faz uma verificação rápida para ver se houve alguma alteração nas dependências do pacote, conforme mencionado no arquivo do projeto (ou nos arquivos dependentes dos projetos) e, se não houver alterações, ele apenas restaurará os pacotes mencionados no arquivo de bloqueio. Não há reavaliações das dependências do pacote.

Se o NuGet detectar uma alteração nas dependências definidas, conforme mencionado nos arquivos de projeto, ele reavaliará o grafo do pacote e atualizará o arquivo de bloqueio para refletir o novo fechamento do pacote para o projeto.

Para CI/CD e outros cenários, em que você não deseja alterar as dependências de pacote rapidamente, é possível configurar o lockedmode como true:

Para dotnet.exe, execute:

> dotnet.exe restore --locked-mode

Para msbuild.exe, execute:

> msbuild.exe -t:restore -p:RestoreLockedMode=true

Você também pode definir essa propriedade condicional do MSBuild em seu arquivo de projeto:

<PropertyGroup>
    <!--- ... -->
    <RestoreLockedMode>true</RestoreLockedMode>
    <!--- ... -->
</PropertyGroup> 

Se o modo de bloqueio for true, a restauração ocorrerá nos pacotes exatos conforme listado no arquivo de bloqueio ou não ocorrerá se você tiver atualizado as dependências de pacote definidas para o projeto após a criação do arquivo de bloqueio.

Tornar o arquivo de bloqueio parte de seu repositório de origem

Se você estiver compilando um aplicativo, um executável e o projeto em questão estarão no início da cadeia da dependência, portanto, verifique o arquivo de bloqueio no repositório do código-fonte para que o NuGet possa utilizá-lo durante a restauração.

No entanto, se seu projeto for um projeto de biblioteca que não é enviado ou um projeto de código comum do qual outros projetos dependem, você não deverá fazer check-in do arquivo de bloqueio como parte de seu código-fonte. Não há mal nenhum em manter o arquivo de bloqueio. No entanto, as dependências do pacote bloqueado do projeto de código comum não podem ser usadas, conforme listado no arquivo de bloqueio, durante a restauração/compilação de um projeto que depende desse projeto de código comum.

Por exemplo:

ProjectA
  |------> PackageX 2.0.0
  |------> ProjectB
             |------>PackageX 1.0.0

Se ProjectA tiver uma dependência em uma versão 2.0.0 do PackageX, além de referências ProjectB que dependem da versão 1.0.0 do PackageX, o arquivo de bloqueio de ProjectB listará uma dependência na versão 1.0.0 do PackageX. No entanto, quando ProjectA for criado, seu arquivo de bloqueio conterá uma dependência na versão 2.0.0 do PackageX e não na versão 1.0.0, conforme listado no arquivo de bloqueio de ProjectB. Portanto, o arquivo de bloqueio de um projeto de código comum tem pouco a dizer sobre os pacotes resolvidos de projetos que dependem dele.

Extensibilidade do arquivo de bloqueio

Você pode controlar vários comportamentos de restauração com o arquivo de bloqueio conforme descrito abaixo:

Opção NuGet.exe opção dotnet Opção equivalente do MSBuild Descrição
-UseLockFile --use-lock-file RestorePackagesWithLockFile Aceita o uso de um arquivo de bloqueio.
-LockedMode --locked-mode RestoreLockedMode Habilita o modo de bloqueio para a restauração. Isso é útil em cenários de CI/CD em que você deseja compilações repetíveis.
-ForceEvaluate --force-evaluate RestoreForceEvaluate Esta opção é útil com pacotes que têm a versão flutuante definida no projeto. Por padrão, a restauração do NuGet não atualizará a versão do pacote automaticamente após cada restauração, a menos que você execute a restauração com essa opção.
-LockFilePath --lock-file-path NuGetLockFilePath Define o local de um arquivo de bloqueio personalizado para um projeto. Por padrão, o NuGet é compatível com packages.lock.json no diretório raiz. Se você tiver vários projetos no mesmo diretório, o NuGet oferecerá suporte ao arquivo de bloqueio packages.<project_name>.lock.json específico do projeto

AssetTargetFallback

A AssetTargetFallback propriedade permite que você especifique versões de estrutura compatíveis adicionais para projetos que seu projeto referencia e pacotes NuGet que seu projeto consome.

Se você especificar uma dependência de pacote usando PackageReference , mas esse pacote não contiver ativos compatíveis com a estrutura de destino de seus projetos, a AssetTargetFallback propriedade entrará em jogo. A compatibilidade do pacote referenciado é verificada novamente usando cada estrutura de destino especificada em AssetTargetFallback. Quando um project ou um package é referenciado por meio AssetTargetFallback, o aviso NU1701 será gerado.

Consulte a tabela abaixo para obter exemplos de como AssetTargetFallback afeta a compatibilidade.

Estrutura do projeto AssetTargetFallback Estruturas de pacote Result
.NET Framework 4.7.2 .NET Standard 2.0 .NET Standard 2.0
Aplicativo .NET Core 3.1 .NET Standard 2.0, .NET Framework 4.7.2 .NET Standard 2.0
Aplicativo .NET Core 3.1 .NET Framework 4.7.2 Incompatível, falha com NU1202
Aplicativo .NET Core 3.1 net472;net471 .NET Framework 4.7.2 .NET Framework 4.7.2 comNU1701

Várias estruturas podem ser especificadas usando ; como delimitador. Para adicionar uma estrutura de fallback, você pode fazer o seguinte:

<AssetTargetFallback Condition=" '$(TargetFramework)'=='netcoreapp3.1' ">
    $(AssetTargetFallback);net472;net471
</AssetTargetFallback>

Você pode deixar de lado $(AssetTargetFallback) se quiser substituir, em vez de adicionar aos valores existentes AssetTargetFallback .

Observação

Se você estiver usando um projeto baseado em SDK do .NET, os valores apropriados $(AssetTargetFallback) serão configurados e você não precisará defini-los manualmente.

$(PackageTargetFallback) foi um recurso anterior que tentou resolver esse desafio, mas é fundamentalmente quebrado e não deve ser usado. Para migrar de $(PackageTargetFallback) para $(AssetTargetFallback), basta alterar o nome da propriedade.