솔루션에서 프로젝트 종속성을 사용하는 경우 MSBuild가 참조 (DLL 파일)를 복사하지 않습니다.


273

내 Visual Studio 솔루션 (.NET 3.5를 대상으로하는 모든 사람)에 네 가지 프로젝트가 있습니다. 제 문제는 다음 두 가지만 중요합니다.

  1. MyBaseProject <-이 클래스 라이브러리는 타사 DLL 파일 (elmah.dll)을 참조합니다
  2. MyWebProject1 <-이 웹 응용 프로그램 프로젝트에는 MyBaseProject에 대한 참조가 있습니다.

"참조 추가 ..."→ "찾아보기"탭 → "elmah.dll"을 선택하여 Visual Studio 2008에서 MyBaseProject 에 elmah.dll 참조를 추가했습니다.

Elmah Reference의 속성은 다음과 같습니다.

  • 별칭-글로벌
  • 로컬 복사-true
  • 문화-
  • 설명-ASP.NET 용 ELMAH (오류 로깅 모듈 및 처리기)
  • 파일 유형-조립
  • 경로-D : \ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
  • 해결됨-참
  • 런타임 버전-v2.0.50727
  • 지정된 버전-false
  • 강력한 이름-거짓
  • 버전-1.0.11211.0

에서 MyWebProject1 나는하여 프로젝트 MyBaseProject에 대한 참조를 추가하십시오 "MyBaseProject"를 선택 → "프로젝트"탭 → "참조 추가 ...". 이 참조의 속성은 다음 멤버를 제외하고 동일합니다.

  • 설명-
  • 경로-D : \ webs \ CMS \ MyBaseProject \ bin \ Debug \ MyBaseProject.dll
  • 버전-1.0.0.0

Visual Studio 에서 빌드를 실행하면 elmah.dll 파일이 MyBaseProject.dll과 함께 MyWebProject1의 bin 디렉토리에 복사됩니다 !

그러나 솔루션에 대해 MSBuild 를 정리하고 실행 하면 (D : \ webs \ CMS> C : \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ MSBuild.exe / t : ReBuild / p : Configuration = Debug MyProject.sln을 통해) ) elmah.dll이 MyWebProject1의 bin 디렉토리에 없습니다-빌드 자체에는 경고 나 오류가 없습니다!

MyBaseProject의 .csproj에 값이 "true"인 개인 요소가 포함되어 있는지 확인했습니다 ( Visual Studio에서 " copy local " 의 별칭이어야 함 ).

<Reference Include="Elmah, Version=1.0.11211.0, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..\mypath\__tools\elmah\Elmah.dll</HintPath>
    **<Private>true</Private>**
</Reference>

(비주얼 스튜디오는 "로컬 복사"가 true라고 말했지만 기본적으로 개인 태그는 .csproj의 xml에 나타나지 않았습니다. "로컬 복사"를 false로 저장했습니다-저장 됨-다시 다시 true로 설정하십시오-저장하십시오!)

MSBuild에 어떤 문제가 있습니까? MyWebProject1의 저장소에 (elmah.dll) 참조를 어떻게 복사합니까?

모든 프로젝트의 빌드 후 명령에 빌드 후 복사 작업을 추가하고 싶지 않습니다! (MyBaseProject에 많은 프로젝트가 의존한다고 가정 해보십시오!)


11
왜 이런 일이 발생했는지에 대한 명확한 대답을 얻고 싶습니다.
David Faivre


1
전체 소스 코드 샘플을 사용하는 최종 솔루션은 무엇입니까?
Kiquenet

2
@deadlydog 의 답변 stackoverflow.com/a/21055664/21579를 참조하십시오 . 훌륭한 설명과 나를 위해 문제를 해결했습니다 ... 아래 가장 투표 된 답변은 VS2012에 맞지 않습니다.
Jeff Widmer

답변:


153

Visual Studio와 MsBuild간에 빌드 할 때 왜 다른지 잘 모르겠지만 MsBuild와 Visual Studio에서이 문제가 발생했을 때 발견 한 내용은 다음과 같습니다.

설명

샘플 시나리오의 경우 프로젝트 X, 어셈블리 A 및 어셈블리 B가 있다고 가정합니다. 어셈블리 A는 어셈블리 B를 참조하므로 프로젝트 X에는 A와 B 모두에 대한 참조가 포함됩니다. 또한 프로젝트 X에는 어셈블리 A를 참조하는 코드 (예 : A)가 포함됩니다. SomeFunction ()). 이제 프로젝트 X를 참조하는 새 프로젝트 Y를 만듭니다.

따라서 종속성 체인은 다음과 같습니다. Y => X => A => B

Visual Studio / MSBuild는 현명 해 지려고 시도하고 프로젝트 X에 필요한 것으로 감지 한 프로젝트 Y에만 참조를 가져옵니다. 프로젝트 Y의 참조 오염을 피하기 위해이를 수행합니다. 문제는 프로젝트 X에 어셈블리 B를 명시 적으로 사용하는 코드 (예 : B.SomeFunction ())를 실제로 포함하지 않기 때문에 VS / MSBuild는 B가 필요하다는 것을 감지하지 못하는 것입니다 X에 의한 것이므로 프로젝트 Y의 bin 디렉토리로 복사하지 않습니다. X 및 A 어셈블리 만 복사합니다.

해결책

이 문제를 해결하기위한 두 가지 옵션이 있습니다. 두 가지 모두 어셈블리 B가 프로젝트 Y의 bin 디렉토리로 복사됩니다.

  1. 프로젝트 Y에서 어셈블리 B에 대한 참조를 추가하십시오.
  2. 어셈블리 B를 사용하는 프로젝트 X의 파일에 더미 코드를 추가하십시오.

개인적으로 몇 가지 이유로 옵션 2를 선호합니다.

  1. 나중에 프로젝트 X를 참조하는 다른 프로젝트를 추가하는 경우 옵션 1과 관련하여 어셈블리 B에 대한 참조도 포함해야합니다.
  2. 왜 더미 코드가 있어야하며 제거하지 말아야 하는지를 명시 적으로 설명 할 수 있습니다. 따라서 누군가 실수로 코드를 삭제 한 경우 (예 : 사용하지 않는 코드를 찾는 리 팩터 도구 등) 소스 제어에서 코드가 필요하다는 것을 쉽게 확인하고 복원 할 수 있습니다. 옵션 1을 사용하고 누군가 리 팩터 도구를 사용하여 사용하지 않는 참조를 정리하는 경우 설명이 없습니다. .csproj 파일에서 참조가 제거되었음을 알 수 있습니다.

다음은이 상황이 발생했을 때 일반적으로 추가하는 "더미 코드"의 샘플입니다.

    // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!!
    private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE()
    {
        // Assembly A is used by this file, and that assembly depends on assembly B,
        // but this project does not have any code that explicitly references assembly B. Therefore, when another project references
        // this project, this project's assembly and the assembly A get copied to the project's bin directory, but not
        // assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never
        // gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well.
        var dummyType = typeof(B.SomeClass);
        Console.WriteLine(dummyType.FullName);
    }

4
여기서 논의되지 않은 것은 웹 프로젝트의 / bin에 빌드 제품을 복사하는 것과 대상 출력 디렉토리에 루틴을 복사하는 것 (예 : / bin / x86 / Debug)간에 차이가 있다는 것입니다. 전자는 참조 된 프로젝트가 빌드 될 때 수행되고 후자는 종속 웹 프로젝트가 수행합니다. Microsoft.Common.targets를 검사하면이를 이해하는 데 도움이됩니다. 웹 / 빈에 대한 복사는 로컬 복사 동작에 전혀 의존하지 않습니다. 복사에 대한 로컬 영향을 출력 대상 디렉토리에 복사합니다. 디버그는 디버그를 통해 실행되는 Cassini가 참조하는 구조의 일부가 아닙니다.
user1164178

6
왜 "더미 코드"를 추가하지 않고 VS와 함께 작동했지만 msbuild가 아닌 이유를 설명 할 수 있습니까?
toebens

3
함수를 호출하는 것보다 덜 침습적이지만 어셈블리 내에 포함 된 클래스 유형을 더미 변수에 할당 할 수 있습니다. Type dummyType = typeof(AssemblyA.AnyClass);
Arithmomaniac

14
Visual Studio에서 '코드 최적화'설정을 선택하지 않으면 위의 솔루션 # 2가 작동합니다. 이 경우 여전히 dll이 제외됩니다. "최적화"를 무시하기 위해 한 줄을 더 추가했습니다. Console.WriteLine(dummyType.FullName);
JasonG

3
솔루션 2는 Visual Studio 2017에서 작동하지 않았습니다. 처음에는 어셈블리 X enum에서 from B 만 사용 하고 열거 형이 인라인 된 것으로 가정 했기 때문에 처음이라고 생각했습니다 . B의 유형을 직접 사용하는 코드를 추가했지만 도움이되지 않았습니다. 또한 내 X가 B의 하위 클래스 유형 인 A의 유형을 사용하는 경우가 항상 있었으므로 컴파일러가 X가 B를 필요로하지 않으며 무시할 수 있다고 생각하는 방식을 이해할 수 없습니다. 이것은 본커입니다.
Xharlie

170

난 그냥 이런 식으로 처리합니다. 참조의 속성으로 이동하여 다음을 수행하십시오.

Set "Copy local = false"
Save
Set "Copy local = true"
Save

그리고 그게 다야.

Visual Studio 2010은 처음에 <private>True</private> 참조 태그를 넣지 않고 "로컬 복사"를 false로 설정하면 태그가 생성됩니다. 그 후에는 그에 따라 true 및 false로 설정됩니다.


10
이것은 신의 선물이었다. 감사합니다!
Rebecca

22
MSBuild 4 / VS2012에서 작동하지 않았습니다. 즉, 말을하기 위해 참조를 업데이트 할 수 <Private>true</Private>있었지만 MSBuild에는 영향을 미치지 않는 것 같습니다. 결국, 하위 프로젝트에 NuGet 참조를 추가했습니다.
Michael Teper

2
나를 위해 일하지 않았다. 여전히 System.Net.Http.Formatting을 bin 폴더에 복사하지 않습니다.
아키라 야마모토

4
이것은에 해당하며 Have you tried turning it off and on again?작동했습니다!
guanome

6
VS2015가 여전히 똑같이 동작하는 것처럼 보입니다 : 'Copy Local'을 'False'로 설정 한 다음 참조 된 .dll에서 'True'로 다시 설정하면 작동합니다.
플립

38

코드에서 직접 어셈블리를 사용하지 않는 경우 Visual Studio는 도움이되는 동안 어셈블리가 사용되지 않고 출력에 포함되지 않음을 감지합니다. 왜 Visual Studio와 MSBuild간에 다른 동작이 나타나는지 잘 모르겠습니다. 빌드 출력을 진단으로 설정하여 둘 다에 대한 결과를 비교할 수 있습니다.

elmah.dll 참조는 코드에서 직접 참조하지 않는 경우 프로젝트에 항목으로 추가하고 빌드 조치 Content를 출력 디렉토리로 복사로 설정할 수 Always있습니다.


3
Elmah가 코드에서 사용되지 않는 경우 출력 디렉토리 주석에 대한 사본에 +1하면 컨텐츠로 복사하는 것이 좋습니다.
키트 Roed

4
실제로 사용되지 않는 어셈블리는 무시하지만 XAML 리소스 사전에서 어셈블리를 사용하는 VS 2010에서는 VS에서 assmebly를 사용하는 것으로 간주되지 않으므로 복사하지 않습니다.
Alex Burtsev


이것은 dll이 필요한 단위 테스트 프로젝트에 더 좋습니다. 메인 프로젝트가 테스트를 실행할 필요가없는 dll을 추가하고 싶지 않습니다!
Lukos

14

보세요:

이 MSBuild 포럼 스레드 시작

내 임시 솔루션 / 해결 방법을 찾을 수 있습니다!

(MyBaseProject는 elmah.dll에서 MyWebProject1의 저장소로 복사하기 위해 elmah.dll에서 일부 클래스를 참조하는 코드가 필요합니다!)


1
젠장-이것이 내가 온 유일한 솔루션입니다-더 좋은 방법이 있기를 바랍니다!
nickspoon

2
덜 해키 솔루션은 아래 앤드류의 reponse 참조 (악의를!)
MPritchard

1
이 문제를 지금보고있는 사람들에게는 MSDN에 대한 toebens의 답변 은 몇 년 후 제공된 Deadlydog의 답변 과 본질적으로 동일 합니다.
jpaugh

8

나는 같은 문제가 있었다.

프로젝트의 프레임 워크 버전이 참조한 dll의 프레임 워크 버전과 동일한 지 확인하십시오.

제 경우에는 제 클라이언트가 "Framework 4 Client"를 사용하여 컴파일되었고 DLL은 "Framework 4"에있었습니다.


6

내가 직면 한 문제는 도서관 프로젝트에 의존하는 프로젝트가 있다는 것입니다. 빌드하기 위해 다음 단계를 수행했습니다.

msbuild.exe myproject.vbproj /T:Rebuild
msbuild.exe myproject.vbproj /T:Package

물론 그것은 내 라이브러리의 dll 파일을 bin과 가장 중요하게 패키지 zip 파일에서 누락했음을 의미합니다. 나는 이것이 완벽하게 작동한다는 것을 알았다.

msbuild.exe myproject.vbproj /T:Rebuild;Package

왜 이것이 작동하는지 또는 왜 처음에는 작동하지 않았는지 전혀 모르겠습니다. 그러나 그것이 도움이되기를 바랍니다.


한 단계에서 TeamCity의 / t : Build를 사용하고 WebAPI 프로젝트의 다음 / t : Package에서 전체 솔루션을 빌드하는 것과 동일한 문제가 발생했습니다. 프로젝트 참조에서 참조한 dll은 포함되지 않았습니다. 이것은 WebAPI에서 위의 / T : Rebuild; Package를 사용하여 수정 된 다음 해당 dll을 포함했습니다.
Andy Hoyle

5

방금 똑같은 문제가 있었고 동일한 솔루션의 두 프로젝트가 다른 버전의 타사 라이브러리를 참조한다는 사실로 인해 발생했습니다.

모든 참조를 수정하면 모든 것이 완벽하게 작동했습니다.


4

Alex Burtsev가 주석에서 XAML 리소스 사전에서만 사용되거나 내 경우에는 XAML에서만 사용되고 코드 숨김이 아닌 것은 MSBuild에서 '사용 중'인 것으로 간주되지 않습니다.

따라서 일부 코드 뒤에 어셈블리의 클래스 / 구성 요소에 대한 더미 참조를 새로 작성하는 것만으로도 MSBuild가 어셈블리가 실제로 사용되고 있음을 확신 할 수 있습니다.


이것은 정확히 내 문제이자 해결책이었습니다. 이것을 알아 내려고 너무 오래 보냈습니다. 감사합니다 Scott & @Alex Burstev
karol

좋은 슬픔, 이것은 나를 미치게했다. , FontAwesome.WPF를 사용했으며 XAML 내 에서만 사용되었습니다 (명백한 이유로). 더미 방법을 추가하면 도움이되었습니다. 감사! 그리고 예, VS 2017 15.6은 여전히 ​​영향을 받으므로
Sören Kuklau

3

에서 대상 프레임 워크 변경 .NET 프레임 워크 4 클라이언트 프로파일.NET 프레임 워크 4는 나를 위해이 문제를 해결했습니다.

예를 들어 MyWebProject1의 대상 프레임 워크를 .NET Framework 4로 설정하십시오.


3

치명적인 계획을 사용하면

Y => X => A => B ,

내 문제는 Y를 빌드 할 때 X의 어셈블리 (A 및 B, 모두 15 개)가 Y의 bin 폴더에 표시되지 않는 것입니다.

Y에서 참조 X를 제거하고 저장하고 빌드 한 다음 X 참조 (프로젝트 참조)를 다시 추가하고 저장하고 빌드하면 A와 B가 Y의 bin 폴더에 표시되기 시작했습니다.


여러 시간 동안 다른 솔루션을 많이 검색하고 시도한 후이 솔루션이 도움이되었습니다.
Suncat2000

2

나는 같은 문제가 있었고 DLL은 동적으로로드 된 참조였습니다. 문제를 해결하기 위해 dll의 네임 스페이스에 "using"을 추가했습니다. 이제 dll이 출력 폴더에 복사됩니다.



2

빌드 중에 사용되지 않은 어셈블리를 참조하는 것은 올바른 방법이 아닙니다. 추가 파일을 복사 할 수 있도록 빌드 파일을 기능 보강해야합니다. 빌드 후 이벤트를 사용하거나 특성 그룹을 업데이트하십시오.

다른 게시물에서 몇 가지 예를 찾을 수 있습니다.


2

이것이 나타나는 또 다른 시나리오는 Visual Studio에서 이전 "웹 사이트"프로젝트 유형을 사용하는 경우입니다. 해당 프로젝트 유형의 경우 자체 디렉토리 구조 (현재 폴더 및 다운) 외부에있는 .dll을 참조 할 수 없습니다. 위의 답변에서 디렉토리 구조가 다음과 같다고 가정 해 봅시다.

여기에 이미지 설명을 입력하십시오

ProjectX와 ProjectY는 부모 / 자식 디렉터리이고 ProjectX는 A.dll을 참조하고 B.dll을 참조하고 B.dll은 루트 (패키지)의 Nuget 패키지, A와 같이 디렉터리 구조 외부에 있습니다. dll은 포함되지만 B.dll은 포함되지 않습니다.


0

나는 오늘 비슷한 문제를 겪었고 이것은 분명히 당신의 질문에 대한 대답이 아닙니다. 하지만 모든 사람에게 알리고 통찰력을 제공하고 싶습니다.

ASP.NET 응용 프로그램이 있습니다. 빌드 프로세스가 정리 된 후 빌드되도록 설정되었습니다.

Jenkins CI 스크립트 가 두 개 있습니다. 하나는 생산 용이고 다른 하나는 준비 용입니다. 스테이징에 응용 프로그램을 배포했으며 모든 것이 잘 작동했습니다. 프로덕션 환경에 배포되었으며 참조 된 DLL 파일이 없습니다. 이 DLL 파일은 프로젝트의 루트에있었습니다. NuGet 리포지토리에 없습니다. DLL이로 설정되었습니다 do not copy.

CI 스크립트와 응용 프로그램은 두 배포간에 동일했습니다. 준비 환경에서 정리 및 배포 후에도 DLL 파일은 ASP.NET 응용 프로그램의 배포 위치 ( bin/) 에서 교체되었습니다 . 프로덕션 환경에서는 그렇지 않았습니다.

테스트 지점에서 빌드 프로세스에 단계를 추가 하여이 DLL 파일을 bin디렉토리 에 복사했습니다 . 이제 알아내는 데 시간이 조금 걸렸습니다. CI 프로세스 자체가 청소되지 않았습니다. DLL이 작업 디렉토리에 남겨져 실수로 ASP.NET .zip 파일로 패키지되었습니다. 프로덕션 브랜치는 DLL 파일을 동일한 방식으로 복사하지 않았으며 실수로이를 배포하지 않았습니다.

TLDR; 빌드 서버가 수행중인 작업을 확인하고 확인하십시오.


0

두 프로젝트가 동일한 .net 버전인지 확인하고 로컬 속성 복사도 확인하지만 이것이 true기본값 이어야합니다.


0

추가 매개 변수 추가 Visual Studio 2015 사용

/ deployonbuild = false

msbuild 명령 줄로 문제를 해결했습니다.


-1

방금 비슷한 문제가 발생했습니다. Visual Studio 2010을 사용하여 컴파일 할 때 DLL 파일이 bin폴더 에 포함되었습니다 . 그러나 MSBuild를 사용하여 컴파일 할 때 타사 DLL 파일은 포함되지 않았습니다.

매우 실망 스럽습니다. 내가 해결 한 방법은 직접 거기에서 사용하지 않아도 웹 프로젝트에 패키지에 대한 NuGet 참조 를 포함시키는 것이 었 습니다.


이것은 최고 답변의 복제본입니다.
Giles Roberts

-3

웹 사이트 프로젝트의 프로젝트 참조에서 참조 된 모든 DLL 파일을 포함시키는 것이 특히 좋은 생각은 아닙니다. 특히 종속성 삽입을 사용 하는 경우 웹 프로젝트는 구체적인 구현 DLL이 아닌 인터페이스 DLL 파일 / 프로젝트에 대한 참조를 추가하려고합니다. 파일.

구현 DLL 파일 / 프로젝트에 직접 참조를 추가하면 개발자가 인터페이스를 통하지 않고 구현 DLL 파일 / 프로젝트의 구체적인 클래스에서 "새"를 호출하는 것을 막을 수 없습니다. 또한 웹 사이트에서 구현을 사용하기 위해 "하드 코드"를 명시했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.