NuGet에서 패키지 종속성을 확인하는 방법

restore 프로세스의 일부로 설치하는 것을 포함하여 패키지를 설치하거나 다시 설치할 때마다 NuGet은 첫 번째 패키지가 종속된 모든 추가 패키지도 설치합니다.

그런 다음 이러한 직접적인 종속성에도 자체의 종속성이 있을 수 있으며, 이에 따라 임의의 수준까지 계속 종속될 수 있습니다. 이렇게 하면 패키지 간의 관계가 모든 수준임을 설명하는 종속성 그래프를 생성합니다.

여러 패키지의 종속성이 같은 경우 동일한 패키지 ID가 그래프에 여러 번 표시될 수 있으며, 잠재적으로 서로 다른 버전 제약 조건이 있을 수 있습니다. 그러나 프로젝트에서 특정 패키지의 한 버전만 사용할 수 있으므로 NuGet은 사용할 버전을 선택해야 합니다. 정확한 프로세스는 사용되는 패키지 관리 형식에 따라 다릅니다.

PackageReference를 사용하여 종속성 확인

PackageReference 형식을 사용하여 패키지를 프로젝트에 설치하는 경우 NuGet은 적절한 파일에서 단순 패키지 그래프에 대한 참조를 추가하고 충돌을 미리 해결합니다. 이 프로세스는 전이적 복원이라고 합니다. 패키지를 다시 설치하거나 복원하면 그래프에 나열된 패키지가 다운로드되어 더 빠르고 예측 가능한 빌드가 수행됩니다.

최신 패키지 버전을 사용하도록 프로젝트를 수정하지 않으려면 부동 버전(예: 2.8.*)을 이용할 수도 있습니다. 부동 버전을 사용하는 경우 반복성을 보장하기 위해 잠금 파일 기능을 사용하도록 설정하는 것이 좋습니다.

NuGet 복원 프로세스가 빌드하기 전에 실행되면, 먼저 메모리에서 종속성을 확인한 다음, 결과 그래프를 project.assets.json이라는 파일에 씁니다.

자산 파일은 기본적으로 프로젝트의 'obj' 폴더인 MSBuildProjectExtensionsPath에 있습니다. 그러면 MSBuild에서 이 파일을 읽고 잠재적인 참조를 찾을 수 있는 폴더의 집합으로 해당 파일을 변환한 다음 메모리의 프로젝트 트리에 추가합니다.

project.assets.json 파일은 임시적이며 원본 제어에 추가하면 안됩니다. .gitignore.tfignore 모두에서 기본적으로 나열됩니다. 패키지 및 원본 제어를 참조하세요.

종속성 확인 규칙

전이적 복원은 종속성을 해결하기 위해 네 가지 기본 규칙을 적용합니다. 가장 낮은 적용 가능한 버전, 부동 버전, 직접 종속성 우선사촌 종속성입니다.

적용 가능한 가장 낮은 버전

적용 가능한 가장 낮은 버전 규칙은 패키지의 종속성으로 정의된 대로 가장 낮은 버전의 패키지를 복원합니다. 유동적인 버전으로 선언되지 않은 경우 애플리케이션 또는 클래스 라이브러리에 대한 종속성에도 적용됩니다.

예를 들어 다음 그림에서 1.0-beta는 1.0보다 낮은 것으로 간주되므로 NuGet은 1.0 버전을 선택합니다.

Choosing the lowest applicable version

다음 그림에서 2.1 버전은 피드에서 사용할 수 없지만 버전 제약 조건이 2.1 이상이므로 이 경우 NuGet에서 찾을 수 있는 버전 중 다음으로 가장 낮은 버전인 2.2를 선택합니다.

Choosing the next lowest version available on the feed

애플리케이션이 피드에서 사용할 수 없는 정확한 버전 번호(예: 1.2)를 지정하면, 패키지를 설치하거나 복원할 때 오류로 인해 NuGet이 실패합니다.

NuGet generates an error when an exact package version is not available

부동 버전

부동 종속성 버전은 * 문자로 지정합니다. 예들 들어 6.0.*입니다. 이 버전 사양에는 "최신 6.0.x 버전 사용"이 표시됩니다. 4.*는 "최신 4.x 버전 사용"을 의미합니다. 부동 버전을 사용하면 최신 버전의 종속성을 유지하면서 프로젝트 파일의 변경 내용을 줄일 수 있습니다. 부동 버전은 프로젝트 수준에서만 지정할 수 있습니다.

부동 버전을 사용하는 경우 NuGet은 버전 패턴과 일치하는 최신 패키지 버전을 확인합니다. 예를 들어 6.0.*는 6.0으로 시작하는 최신 패키지 버전을 가져옵니다.

Choosing version 6.0.1 when a floating version 6.0.* is requested

버전 서버에 표시되는 버전 해결 원인 주의
* 1.1.0
1.1.1
1.2.0
1.3.0-alpha
1.2.0 안정적인 최상 버전입니다.
1.1.* 1.1.0
1.1.1
1.1.2-alpha
1.2.0-alpha
1.1.1 지정된 패턴을 따르는 안정적인 최상 버전입니다.
*-* 1.1.0
1.1.1
1.1.2-alpha
1.3.0-beta
1.3.0-beta 불안정한 버전을 포함하는 최상 버전입니다. Visual Studio 버전 16.6, NuGet 버전 5.6, .NET Core SDK 버전 3.1.300에서 사용 가능
1.1.*-* 1.1.0
1.1.1
1.1.2-alpha
1.1.2-beta
1.3.0-beta
1.1.2-beta 불안정한 버전을 포함하며 패턴을 따르는 최상 버전입니다. Visual Studio 버전 16.6, NuGet 버전 5.6, .NET Core SDK 버전 3.1.300에서 사용 가능

참고 항목

부동 버전 확인은 패키지가 나열되는지 여부를 고려하지 않습니다. 전역 패키지 폴더의 패키지에 조건이 충족될 수 있는 경우 부동 버전 확인이 로컬로 해결됩니다.

직접 종속성 우선

애플리케이션에 대한 패키지 그래프에 동일한 하위 그래프에 패키지의 다른 버전이 포함되어 있고 해당 버전 중 하나가 해당 하위 그래프의 직접 종속성인 경우 해당 버전은 해당 하위 그래프에 대해 선택되고 나머지는 무시됩니다. 이 동작을 통해 애플리케이션에서 종속성 그래프의 특정 패키지 버전을 재정의할 수 있습니다.

아래 예제에서 애플리케이션은 버전 제약 조건이 >=2.0.0인 패키지 B에 직접 의존합니다. 또한 애플리케이션은 패키지 A에 따라 달라지며 패키지 B에 따라 달라지지만 >=1.0.0 제약 조건이 적용됩니다. 패키지 B 2.0.0에 대한 종속성은 그래프의 애플리케이션에 대한 직접 종속성이므로 해당 버전이 사용됩니다.

Application using the Direct dependency wins rule

Warning

직접 종속성 우선 규칙으로 인해 패키지 버전이 다운그레이드되어 그래프의 다른 종속성이 손상될 수 있습니다. 패키지가 다운그레이드되면 NuGet은 사용자에게 경고하는 경고를 추가합니다.

또한 이 규칙은 큰 종속성 그래프 통해 효율성을 높입니다. 동일한 하위 그래프의 종속성이 더 높은 버전보다 높은 경우 NuGet은 해당 종속성을 무시하고 NuGet은 그래프의 해당 분기에 대한 종속성을 다시 기본 모두 무시합니다.

예를 들어 아래 다이어그램에서 패키지 C 2.0.0이 사용되므로 NuGet은 이전 버전의 패키지 C를 참조하는 하위 그래프의 모든 분기를 무시합니다.

When NuGet ignores a package in the graph, it ignores that entire branch

이 규칙을 통해 NuGet은 패키지 작성자의 의도를 적용하려고 합니다. 아래 다이어그램에서 패키지 A의 작성자가 명시적으로 패키지 C 2.0.0에서 패키지 C 1.0.0으로 다운그레이드했습니다.

When a package author explicitly downgrades, NuGet honors that.

애플리케이션 소유자는 패키지 C를 2.0.0보다 높은 버전으로 업그레이드하도록 선택할 수 있으므로 패키지 C에 대한 버전을 더 이상 다운그레이드할 수 없습니다. 이 경우 경고가 발생하지 않습니다.

When an application honor adds a direct dependency for a downgraded package, NuGet honors that.

사촌 종속성

애플리케이션과 그래프의 다른 하위 그래프에서 다른 패키지 버전을 참조하는 경우 NuGet은 모든 버전 요구 사항을 충족하는 가장 낮은 버전을 사용합니다(가장 낮은 적용 가능한 버전 및 부동 버전 규칙과 마찬가지로). 예를 들어 아래 이미지에서 패키지 B의 버전 2.0.0은 다른 >=1.0.0 제약 조건을 충족하므로 다음과 같이 사용됩니다.

Resolving cousin dependencies using the lower version that satisfies all constraints

사촌 종속성 규칙을 적용하기 위해 패키지가 동일한 거리에 있을 필요는 없습니다. 아래 다이어그램에서 패키지 D 2.0.0은 패키지 C 하위 그래프에서 선택되고 패키지 D 3.0.0은 패키지 A의 하위 그래프에서 선택됩니다. 애플리케이션 하위 그래프에는 패키지 D에 대한 직접 종속성이 없으므로 가장 낮은 적용 가능한 버전 규칙이 적용되고 버전 3.0.0이 선택됩니다.

Resolving cousin dependencies using the lower version that satisfies all constraints at different distances

모든 버전 요구 사항을 충족할 수 없는 경우도 있습니다. 아래와 같이 패키지 A에 정확히 패키지 B 1.0.0이 필요하고 패키지 C에 패키지 B >=2.0.0이 필요한 경우 NuGet은 종속성을 해결할 수 없으며 오류를 제공합니다.

Unresolvable dependencies due to an exact version requirement

이러한 경우 최상위 소비자(애플리케이션 또는 패키지)는 직접 종속성 우선 규칙이 적용되도록 패키지 B에 대한 자체 직접 종속성을 추가해야 합니다.

packages.config를 사용하여 종속성 확인

packages.config를 사용하면 프로젝트의 종속성이 단순 목록으로 packages.config에 기록됩니다. 이러한 패키지의 모든 종속성도 동일한 목록에 기록됩니다. 패키지가 설치되면 NuGet에서 .csproj 파일, app.config, web.config 및 기타 개별 파일을 수정할 수도 있습니다.

packages.config를 사용하면 NuGet은 각각의 개별 패키지를 설치하는 동안 종속성 충돌을 해결하려고 합니다. 즉 A 패키지가 설치되고 B 패키지에 종속되어 있고 B 패키지가 이미 다른 패키지의 종속성으로 packages.config에 나열되어 있는 경우, NuGet은 요청된 B 패키지의 버전을 비교하고 모든 버전 제약 조건을 충족하는 버전을 찾으려고 합니다. 특히 NuGet은 종속성을 충족하는 더 낮은 major.minor 버전을 선택합니다.

기본적으로 NuGet 2.8은 가장 낮은 패치 버전을 찾습니다(NuGet 2.8 릴리스 정보 참조). NuGet.ConfigDependencyVersion 특성 및 명령줄의 -DependencyVersion 스위치를 통해 이 설정을 제어할 수 있습니다.

더 큰 종속성 그래프의 경우 종속성을 확인하기 위한 packages.config 프로세스가 복잡해집니다. 새 패키지를 설치할 때마다 그래프 전체를 통과해야 하며 버전 충돌이 발생할 가능성이 높습니다. 충돌이 발생하면 특히 프로젝트 파일 자체를 잠재적으로 수정하여 설치가 중지되고 프로젝트가 확정되지 않은 상태로 유지됩니다. 다른 패키지 관리 형식을 사용하는 경우에는 문제가 되지 않습니다.

종속성 자산 관리

PackageReference 형식을 사용하는 경우 종속성에서 최상위 프로젝트로 이동하는 자산을 제어할 수 있습니다. 자세한 내용은 PackageReference를 참조하세요.

또한 최상위 프로젝트 자체가 패키지인 경우 .nuspec 파일에 나열된 종속성이 있는 includeexclude 특성을 사용하여 이 흐름을 제어할 수도 있습니다. .nuspec 참조 - 종속성을 참조하세요.

참조 제외

프로젝트에서 동일한 이름의 어셈블리를 두 번 이상 참조하여 디자인 타임 및 빌드 시간 오류를 생성할 수 있는 시나리오가 있습니다. C.dll의 사용자 지정 버전을 포함하고 C.dll도 포함된 C 패키지를 참조하는 프로젝트를 생각해 보세요. 동시에 이 프로젝트는 C 패키지와 C.dll에도 종속된 B 패키지에 종속됩니다. 결과적으로 NuGet은 사용할 C.dll을 결정할 수 없지만 B 패키지도 이에 종속되기 때문에 C 패키지에 대한 프로젝트의 종속성을 제거할 수 없습니다.

이 문제를 해결하려면, 원하는 C.dll을 직접 참조하거나 올바른 패키지를 참조하는 다른 패키지를 사용한 다음, 해당 자산을 모두 제외하는 C 패키지에 대한 종속성을 추가해야 합니다. 이렇게 하려면 사용 중인 패키지 관리 형식에 따라 다음과 같이 수행합니다.

  • PackageReference: 종속성에 ExcludeAssets="All"을 추가합니다.

    <PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
    
  • packages.config: 원하는 C.dll 버전만 참조하도록 .csproj 파일에서 PackageC에 대한 참조를 제거합니다.

패키지 설치 중 종속성 업데이트

종속성 버전이 이미 충족된 경우 다른 패키지를 설치하는 동안 종속성이 업데이트되지 않습니다. 예를 들어 B 패키지에 종속된 A 패키지를 고려하고 버전 번호를 1.0으로 지정합니다. 소스 리포지토리에는 B 패키지의 버전 1.0, 1.1 및 1.2가 포함되어 있습니다. B 버전 1.0이 이미 포함된 프로젝트에 A가 설치된 경우 B 1.0은 버전 제약 조건을 충족하므로 계속 사용됩니다. 그러나 A 패키지에서 1.1 버전 이상의 B를 요청하면 B 1.2가 설치됩니다.

호환되지 않는 패키지 오류 해결

패키지 복원 작업 중에 "하나 이상의 패키지가 호환되지 않습니다..." 또는 패키지가 프로젝트의 대상 프레임워크와 "호환되지 않습니다."라는 오류가 표시될 수 있습니다.

프로젝트에서 참조하는 하나 이상의 패키지에서 프로젝트의 대상 프레임워크를 지원하지 않는다고 나타내는 경우에 이 오류가 발생합니다. 즉 패키지에는 프로젝트와 호환되는 대상 프레임워크에 대한 lib 폴더에 적합한 DLL이 포함되지 않습니다. (목록은 대상 프레임워크를 참조하세요.)

예를 들어 프로젝트에서 netstandard1.6을 대상으로 하고 lib\net20\lib\net45 폴더에만 DLL이 포함되는 패키지를 설치하려고 하면 패키지 및 해당 종속 항목에 대해 다음과 같은 메시지가 표시됩니다.

Restoring packages for myproject.csproj...
Package ContosoUtilities 2.1.2.3 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoUtilities 2.1.2.3 supports:
  - net20 (.NETFramework,Version=v2.0)
  - net45 (.NETFramework,Version=v4.5)
Package ContosoCore 0.86.0 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoCore 0.86.0 supports:
  - 11 (11,Version=v0.0)
  - net20 (.NETFramework,Version=v2.0)
  - sl3 (Silverlight,Version=v3.0)
  - sl4 (Silverlight,Version=v4.0)
One or more packages are incompatible with .NETStandard,Version=v1.6.
Package restore failed. Rolling back package changes for 'MyProject'.

비호환성을 해결하려면 다음 중 하나를 수행합니다.

  • 프로젝트의 대상을 사용할 패키지에서 지원하는 프레임워크로 변경합니다.
  • 패키지 작성자에게 문의하고 선택한 프레임워크에 대한 지원을 추가합니다. nuget.org의 각 패키지 목록 페이지에는 이 목적을 위한 연락처 소유자 링크가 있습니다.

대체 솔루션: NuGetSolver는 종속성 충돌 해결을 지원하도록 설계된 Microsoft DevLabs에서 개발한 Visual Studio 확장입니다. 이러한 문제를 식별하고 해결하는 프로세스를 자동화합니다. 자세한 내용은 Visual Studio Marketplace의 NuGetSolver 페이지를 방문하여 사용자 환경에 대한 피드백을 듣고 싶습니다.