Dependências

A principal maneira de adicionar as dependências em uma biblioteca do .NET fazer referência a pacotes do NuGet. Referências de pacote do NuGet permitem que você rapidamente reutilize e aproveite a funcionalidade já escrita, mas são uma fonte comum de atrito para desenvolvedores do .NET. Gerenciar dependências corretamente é importante para evitar que alterações em outras bibliotecas .NET provoquem falhas na sua biblioteca do .NET e vice-versa.

Dependências de losango

É comum um projeto que um projeto .NET tenha várias versões de um pacote em sua árvore de dependência. Por exemplo, um aplicativo depende de dois pacotes NuGet, cada um dos quais depende de versões diferentes do mesmo pacote. Agora existe uma dependência de losango no grafo de dependência do aplicativo.

Diamond dependency

No momento da compilação, o NuGet analisa todos os pacotes de que um projeto depende, incluindo as dependências das dependências. Quando várias versões de um pacote são detectadas, as regras são avaliadas para escolher uma. Unificar pacotes é necessário porque executar versões lado a lado de um assembly no mesmo aplicativo é um problema no .NET.

A maioria das dependências de losangos é facilmente resolvida. No entanto, podem criar problemas em determinadas circunstâncias:

  • Referências de pacote do NuGet conflitantes impedem que uma versão seja resolvida durante a restauração de pacote.
  • Alterações interruptivas entre as versões causam erros e exceções em tempo de execução.
  • O assembly do pacote tem um nome forte, a versão do assembly é alterada e o aplicativo está em execução no .NET Framework. Redirecionamentos de associação de assembly são necessários.

Não é possível saber quais pacotes serão usados junto com o seu. Uma boa maneira de reduzir a probabilidade de uma dependência de losango provocar falha na sua biblioteca é minimizar o número de pacotes dos quais você depende.

✔️ FAÇA a análise da sua biblioteca do .NET quanto a dependências desnecessárias.

Intervalos de versão de dependência do NuGet

Uma referência de pacote especifica o intervalo de pacotes válidos que ela permite. De modo geral, a versão de referência do pacote no arquivo do projeto é a versão mínima, e não há um máximo.

<!-- Accepts any version 1.0 and above. -->
<PackageReference Include="ExamplePackage" Version="1.0" />

As regras que o NuGet usa ao resolver as dependências são complexas, mas o NuGet procura por padrão sempre a versão mais antiga aplicável. O NuGet prefere a versão mais antiga aplicável, em vez de usar a mais alta disponível, porque a mais baixa terá menos problemas de compatibilidade.

Devido à regra de versão mais baixa aplicável do NuGet, não é necessário colocar uma versão superior ou o intervalo exato em referências de pacote para evitar obter a versão mais recente. O NuGet já tenta encontrar a versão mais baixa e mais compatível para você.

<!-- Accepts 1.0 up to 1.x, but not 2.0 and higher. -->
<PackageReference Include="ExamplePackage" Version="[1.0,2.0)" />

<!-- Accepts exactly 1.0. -->
<PackageReference Include="ExamplePackage" Version="[1.0]" />

Limites de versão superior fará com que o NuGet falhe se houver um conflito. Por exemplo, uma biblioteca aceita exatamente 1.0, enquanto a outra biblioteca exige 2.0 ou superior. Embora alterações da falha possam ter sido introduzidas na versão 2.0, uma dependência de versão do limite superior ou estrita garantirá um erro.

Diamond dependency conflict

❌ NÃO tenha referências de pacote do NuGet sem versão mínima.

❌ EVITAR referências do pacote NuGet que demandam uma versão exata.

❌ EVITAR referências ao pacote NuGet com um limite superior de versão.

Para obter mais informações, consulte Controle de versão de pacote.

Pacotes de código-fonte compartilhado do NuGet

Uma maneira de reduzir as dependências externas do pacote NuGet é fazer referência a pacotes de origem compartilhados. Um pacote de origem compartilhado contém arquivos de código-fonte incluídos em um projeto quando referenciados. Como você está apenas incluindo arquivos de código-fonte compilados com o restante do seu projeto, não há dependência externa nem chance de conflito.

Pacotes de origem compartilhados são ótimos para incluir pequenas funcionalidades. Por exemplo, você poderia fazer referência a um pacote de origem compartilhado de métodos de assistência para fazer chamadas HTTP.

Shared source package

<PackageReference Include="Microsoft.Extensions.Buffers.Testing.Sources" PrivateAssets="All" Version="1.0" />

Shared source project

Pacotes de origem compartilhado têm algumas limitações. Eles só podem ser referenciados por PackageReference, portanto, projetos packages.config mais antigos são excluídos. Além disso, pacotes de origem compartilhados são utilizáveis somente por projetos com a mesma linguagem. Devido a essas limitações, os pacotes de origem compartilhados devem ser usados, de preferência, para compartilhar funcionalidades dentro de um projeto de código aberto.

✔️ CONSIDERE fazer referência a de código-fonte compartilhados para pequenas funcionalidades internas.

✔️ CONSIDERE tornar seu pacote de um pacote de origem compartilhado se ele oferecer pequenas funcionalidades internas.

✔️ FAÇA referência a pacotes de origem compartilhados com PrivateAssets="All".

Essa configuração informa que o pacote do NuGet deve ser usado apenas no tempo de desenvolvimento e não deve ser exposto como uma dependência pública.

❌ NÃO tenha tipos de pacote de origem compartilhados na sua API pública.

Tipos de origem compartilhada são compilados no assembly de referência e não podem ser trocados entre os limites de assembly. Por exemplo, um tipo IRepository de origem compartilhada em um projeto é um tipo separado do mesmo IRepository de origem compartilhada em outro projeto. Tipos em pacotes de origem compartilhados devem ter uma visibilidade internal.

❌ NÃO publique pacotes de origem compartilhados em NuGet.org.

Pacotes de origem compartilhados contêm código-fonte e só podem ser usados por projetos com o mesmo tipo de linguagem. Por exemplo, um pacote de origem compartilhado em C# não pode ser usado por um aplicativo em F#.

Publicar pacotes de origem compartilhados em um feed local ou no MyGet para consumi-los internamente dentro de seu projeto.