NuGet 패키지 관리
이 스킬을 사용해야 하는 경우
다음과 같은 경우에 이 스킬을 사용하세요:
- NuGet 패키지 추가, 제거 또는 업데이트
- 솔루션에 대한 중앙 패키지 관리(CPM) 설정
- 여러 프로젝트에서 패키지 버전 관리
- 패키지 충돌 또는 복원 문제 해결
황금률: XML을 직접 편집하지 마세요
패키지 관리를 위해 항상 dotnet CLI 명령어를 사용하세요. .csproj 또는 Directory.Packages.props 파일을 수동으로 편집하지 마세요.
# 권장: CLI 명령어 사용
dotnet add package Newtonsoft.Json
dotnet remove package Newtonsoft.Json
dotnet list package --outdated
# 비권장: XML 직접 편집
# <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
이유:
- CLI는 패키지가 존재하고 올바른 버전을 확인합니다.
- 전이 종속성을 올바르게 처리합니다.
- 잠금 파일이 있으면 업데이트합니다.
- 오타 및 잘못된 XML을 방지합니다.
- CPM과 올바르게 작동합니다.
중앙 패키지 관리(CPM)
CPM은 모든 패키지 버전을 하나의 파일에 중앙 집중화하여 프로젝트 간 버전 충돌을 제거합니다.
CPM 활성화
솔루션 루트에 Directory.Packages.props를 생성하세요:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Serilog" Version="4.0.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
</ItemGroup>
</Project>
CPM을 사용하는 프로젝트 파일
프로젝트는 버전 없이 패키지를 참조합니다:
<!-- src/MyApp/MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
</Project>
CPM으로 패키지 추가하기
# Directory.Packages.props와 프로젝트 파일에 모두 추가됩니다.
dotnet add package Serilog.Sinks.Console
# Directory.Packages.props 결과:
# <PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
# 프로젝트 파일 결과:
# <PackageReference Include="Serilog.Sinks.Console" />
공유 버전 변수
관련 패키지를 공유 버전 변수로 그룹화하세요:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- 공유 버전 변수 -->
<PropertyGroup Label="SharedVersions">
<AkkaVersion>1.5.59</AkkaVersion>
<AkkaHostingVersion>1.5.59</AkkaHostingVersion>
<AspireVersion>9.0.0</AspireVersion>
<OpenTelemetryVersion>1.11.0</OpenTelemetryVersion>
<XunitVersion>2.9.2</XunitVersion>
</PropertyGroup>
<!-- Akka.NET 패키지 - 모두 동일한 버전 사용 -->
<ItemGroup Label="Akka.NET">
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster.Sharding" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster.Tools" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Streams" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Hosting" Version="$(AkkaHostingVersion)" />
<PackageVersion Include="Akka.Cluster.Hosting" Version="$(AkkaHostingVersion)" />
</ItemGroup>
<!-- Aspire 패키지 -->
<ItemGroup Label="Aspire">
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
</ItemGroup>
<!-- OpenTelemetry 패키지 -->
<ItemGroup Label="OpenTelemetry">
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="$(OpenTelemetryVersion)" />
</ItemGroup>
<!-- 테스트 -->
<ItemGroup Label="Testing">
<PackageVersion Include="xunit" Version="$(XunitVersion)" />
<PackageVersion Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="Verify.Xunit" Version="26.0.0" />
</ItemGroup>
</Project>
이점:
- 하나의 변수를 변경하여 모든 Akka 패키지를 업데이트합니다.
- 레이블이 지정된 ItemGroup으로 명확하게 구성합니다.
- 관련 패키지의 버전 불일치를 방지합니다.
CPM을 사용하지 말아야 할 경우
중앙 패키지 관리가 항상 올바른 선택은 아닙니다:
레거시 프로젝트
기존의 대규모 솔루션을 CPM으로 마이그레이션하면 문제가 발생할 수 있습니다:
- 기존 버전 충돌이 한 번에 모두 표시됩니다.
- 일부 패키지는 의도적으로 버전이 다를 수 있습니다.
- 마이그레이션하려면 동시에 많은 파일을 수정해야 합니다.
권장 사항: 레거시 프로젝트의 경우 점진적으로 마이그레이션하거나, 현재 방식이 잘 작동한다면 프로젝트별 버전 관리를 유지하세요.
버전 범위
CPM은 정확한 버전이 필요합니다. 버전 범위를 지원하지 않습니다:
<!-- CPM에서는 지원되지 않음 -->
<PackageVersion Include="Newtonsoft.Json" Version="[13.0,14.0)" />
<!-- 정확한 버전을 사용해야 함 -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
버전 범위가 필요한 경우(드물지만 일부 라이브러리 시나리오에서 필요), CPM은 작동하지 않습니다.
이전 .NET 버전
CPM에는 다음이 필요합니다:
- .NET SDK 6.0.300+ 이상
- NuGet 6.2+ 이상
- Visual Studio 2022 17.2+ 이상
이전 SDK 버전을 대상으로 하거나 팀 구성원이 이전 도구를 사용하는 경우 CPM으로 인해 빌드 오류가 발생할 수 있습니다.
다중 저장소 솔루션
솔루션이 독립적으로 빌드되는 여러 저장소에 걸쳐 있는 경우, CPM의 단일 Directory.Packages.props 파일은 도움이 되지 않습니다. 각 저장소에 자체 파일이 필요합니다.
CLI 명령어 참조
패키지 추가하기
# 최신 안정 버전 추가
dotnet add package Serilog
# 특정 버전 추가
dotnet add package Serilog --version 4.0.0
# 시험판 추가
dotnet add package Serilog --prerelease
# 특정 프로젝트에 추가
dotnet add src/MyApp/MyApp.csproj package Serilog
패키지 제거하기
# 현재 프로젝트에서 제거
dotnet remove package Serilog
# 특정 프로젝트에서 제거
dotnet remove src/MyApp/MyApp.csproj package Serilog
패키지 나열하기
# 솔루션의 모든 패키지 나열
dotnet list package
# 업데이트 가능한 패키지 표시
dotnet list package --outdated
# 전이 종속성 포함
dotnet list package --include-transitive
# 취약한 패키지 표시
dotnet list package --vulnerable
# 사용되지 않는 패키지 표시
dotnet list package --deprecated
패키지 업데이트하기
# CPM 사용 시: Directory.Packages.props에서 버전 편집
# 그런 다음 복원하여 적용
dotnet restore
# CPM 미사용 시: 새 버전으로 제거 및 추가
dotnet remove package Serilog
dotnet add package Serilog --version 4.1.0
# 또는 dotnet-outdated 도구 사용 (권장)
dotnet tool install --global dotnet-outdated-tool
dotnet outdated --upgrade
복원 및 정리
# 패키지 복원
dotnet restore
# 로컬 캐시 지우기 (문제 해결)
dotnet nuget locals all --clear
# 강제 복원 (캐시 무시)
dotnet restore --force
패키지 소스
소스 나열하기
dotnet nuget list source
비공개 피드 추가하기
# 인증된 피드 추가
dotnet nuget add source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
--name MyFeed \
--username az \
--password $PAT \
--store-password-in-clear-text
NuGet.config
솔루션별 소스의 경우 NuGet.config를 생성하세요:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyPrivateFeed" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<MyPrivateFeed>
<add key="Username" value="az" />
<add key="ClearTextPassword" value="%NUGET_PAT%" />
</MyPrivateFeed>
</packageSourceCredentials>
</configuration>
일반적인 패턴
개발 전용 패키지
<!-- Directory.Packages.props -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<!-- 프로젝트 파일 - 개발 종속성으로 표시 -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
조건부 패키지
<!-- Debug 빌드에만 포함 -->
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="JetBrains.Annotations" />
</ItemGroup>
<!-- 플랫폼별 -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Text.Json" />
</ItemGroup>
버전 재정의 (탈출구)
하나의 프로젝트에 대해 CPM을 재정의해야 하는 경우(드물게):
<!-- 프로젝트 파일 - 드물게 사용하세요! -->
<PackageReference Include="Newtonsoft.Json" VersionOverride="12.0.3" />
경고: 이는 Slopwatch(dotnet/slopwatch 스킬 참조)에서 잠재적인 슬롭으로 감지됩니다.
문제 해결
버전 충돌
# 전체 종속성 트리 보기
dotnet list package --include-transitive
# 특정 패키지를 참조하는 항목 찾기
dotnet list package --include-transitive | grep -i "PackageName"
복원 실패
# 모든 캐시 지우기
dotnet nuget locals all --clear
# 상세 로깅과 함께 복원
dotnet restore --verbosity detailed
# 잠긴 패키지 확인
cat packages.lock.json
잠금 파일
재현 가능한 빌드를 위해 패키지 잠금 파일을 사용하세요:
<!-- Directory.Build.props -->
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
그런 다음 packages.lock.json 파일을 커밋하세요.
안티 패턴
하지 말아야 할 것: XML 직접 편집
<!-- 나쁨: 수동 XML 편집 -->
<PackageReference Include="Typo.Package" Version="1.0.0" />
<!-- 패키지가 존재하지 않을 수 있습니다! CLI가 이를 감지합니다. -->
하지 말아야 할 것: CPM과 함께 인라인 버전 사용
<!-- 나쁨: CPM 우회 -->
<PackageReference Include="Serilog" Version="4.0.0" />
<!-- 좋음: 버전이 Directory.Packages.props에서 가져옴 -->
<PackageReference Include="Serilog" />
하지 말아야 할 것: 버전 관리 혼합
<!-- 나쁨: 일부 버전은 CPM, 일부는 인라인 -->
<PackageReference Include="Serilog" /> <!-- CPM에서 -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <!-- 인라인 -->
하지 말아야 할 것: 공유 변수 사용 잊기
<!-- 나쁨: 관련 패키지가 다른 버전을 가짐 -->
<PackageVersion Include="Akka" Version="1.5.59" />
<PackageVersion Include="Akka.Cluster" Version="1.5.58" /> <!-- 불일치! -->
<!-- 좋음: 공유 변수 사용 -->
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
빠른 참조
| 작업 | 명령어 |
|---|---|
| 패키지 추가 | dotnet add package <name> |
| 특정 버전 추가 | dotnet add package <name> --version <ver> |
| 패키지 제거 | dotnet remove package <name> |
| 패키지 나열 | dotnet list package |
| 업데이트 가능 항목 표시 | dotnet list package --outdated |
| 취약한 항목 표시 | dotnet list package --vulnerable |
| 복원 | dotnet restore |
| 캐시 지우기 | dotnet nuget locals all --clear |