No desenvolvimento de soluções .NET complexas, manter a consistência das versões dos pacotes NuGet entre múltiplos projetos pode ser desafiador. O arquivo Directory.Build.props oferece uma solução eficiente para definir variáveis globais de versão.
Este arquivo especial, localizado na raiz da solução ou em um diretório pai compartilhado, é automaticamente importado pelo MSBuild em todos os projetos. Para ambientes multi-produto, é recomendável colocar um arquivo Directory.Build.props no diretório raiz de cada produto para isolar suas dependências.
Uma boa prática é utilizar grupos de propriedades (PropertyGroup) para organizar as variáveis. A convenção de nomenclatura para as versões pode substituir pontos por sublinhados e adicionar um sufixo, como _Versao.
Exemplo de um arquivo Directory.Build.props básico:
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);NU1603;CS8618</NoWarn>
<InformacaoProduto>Minha Aplicacao Corporativa</InformacaoProduto>
</PropertyGroup>
<PropertyGroup Label="VersoesExternas">
<VersaoFrameworkAbp>8.1.0</VersaoFrameworkAbp>
<Versao_BibliotecaX>4.5.*-*</Versao_BibliotecaX>
<Versao_PacoteIdentityModel>6.2.0</Versao_PacoteIdentityModel>
</PropertyGroup>
<PropertyGroup Label="VersoesAspNetCore">
<Versao_AspNetCore>7.0.10</Versao_AspNetCore>
<Versao_AspNetCore_Rewriter>2.3.0</Versao_AspNetCore_Rewriter>
</PropertyGroup>
</Project>
Para consumir essas variáveis em um projeto filho, utiliza-se a sintaxe de variáveis do MSBuild $(NomeDaVariavel) no atributo Version do pacote.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" Version="$(VersaoFrameworkAbp)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="$(Versao_AspNetCore)" />
<PackageReference Include="Meu.Pacote.Interno.Core" Version="$(Versao_MeuPacote_Core)" />
</ItemGroup>
</Project>
Em arquiteturas modulares, como as construídas com o framework ABP, é vantajoso isolar as versões de cada módulo em arquivos separados dentro de uma pasta, por exemplo, configuracoes-versoes.
<!-- Arquivo: configuracoes-versoes/VersoesModuloFinanceiro.props -->
<Project>
<PropertyGroup>
<Versao_ModuloFinanceiro>2024.1.250</Versao_ModuloFinanceiro>
</PropertyGroup>
</Project>
O arquivo principal importa então todos esses módulos:
<!-- Directory.Build.props na raiz do produto -->
<Project>
<Import Project="configuracoes-versoes/VersoesModuloFinanceiro.props" />
<Import Project="configuracoes-versoes/VersoesModuloIdentidade.props" />
<PropertyGroup>
<VersaoFrameworkAbp>8.1.0</VersaoFrameworkAbp>
<!-- Outras configurações comuns -->
</PropertyGroup>
</Project>
Para automatizar a atualiazção dessas versões, pipelines de CI/CD, como o GitLab CI, podem ser configurados. Após etapas de compilação e teste, um job dedicado pode autalizar os arquivos de versão via SSH.
atualizar_versoes_modulo:
stage: deploy
script:
- ssh usuario@servidor "sed -i 's/<Versao_ModuloFinanceiro>.*<\/Versao_ModuloFinanceiro>/<Versao_ModuloFinanceiro>$NOVA_VERSAO<\/Versao_ModuloFinanceiro>/g' /caminho/para/configuracoes-versoes/VersoesModuloFinanceiro.props"
As equipes de desenvolvimento podem sincronizar suas versões locais usando um script simples que baixa os arquivos de um servidor de artefatos. Um exemplo de script em lote para Windows (sincronizar-versoes.bat):
@echo off
set "URL_BASE=https://artefatos.empresa.com/versoes/"
set "PASTA_DESTINO=%~dp0configuracoes-versoes"
mkdir "%PASTA_DESTINO%" 2>nul
for %%f in (VersoesModuloFinanceiro.props VersoesModuloIdentidade.props Directory.Build.props) do (
curl -o "%PASTA_DESTINO%\%%f" "%URL_BASE%%%f"
)
echo Versoes sincronizadas.
Em ambientes de contêiner, o Dockerfile pode incluir a etapa de cópia dos arquivos de configuração de versão antes do restore e build:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copiar arquivos de definição de versões
COPY ["Directory.Build.props", "."]
COPY ["configuracoes-versoes/", "configuracoes-versoes/"]
COPY ["Meu.Projeto.csproj", "."]
RUN dotnet restore "Meu.Projeto.csproj"
COPY . .
RUN dotnet publish "Meu.Projeto.csproj" -c Release -o /app/publish
Esta abordagem garante que todas as compilações, sejam locais, em CI ou em contêineres, utilizem exatamente as mesmas versões de pacotes, proporcionando reprodutibilidade e controle total sobre as dependências.