MSBuild không sao chép tài liệu tham khảo (tệp DLL) nếu sử dụng phụ thuộc dự án trong giải pháp


273

Tôi có bốn dự án trong giải pháp Visual Studio của mình (mọi người nhắm mục tiêu .NET 3.5) - đối với vấn đề của tôi chỉ có hai dự án này là quan trọng:

  1. MyBaseProject <- thư viện lớp này tham chiếu tệp DLL của bên thứ ba (elmah.dll)
  2. MyWebProject1 <- dự án ứng dụng web này có tham chiếu đến MyBaseProject

Tôi đã thêm tham chiếu elmah.dll vào MyBaseProject trong Visual studio 2008 bằng cách nhấp vào "Thêm tham chiếu ..." → "Duyệt" tab → chọn "elmah.dll".

Các thuộc tính của tài liệu tham khảo Elmah như sau:

  • Bí danh - toàn cầu
  • Sao chép cục bộ - đúng
  • Văn hóa -
  • Mô tả - Các mô-đun và trình xử lý ghi nhật ký lỗi (ELMAH) cho ASP.NET
  • Loại tệp - Hội
  • Đường dẫn - D: \ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
  • Đã giải quyết - Đúng
  • Phiên bản thời gian chạy - v2.0.50727
  • Phiên bản được chỉ định - sai
  • Tên mạnh - sai
  • Phiên bản - 1.0.11211.0

Trong MyWebProject1 tôi đã thêm tham chiếu vào Project MyBaseProject bằng cách: "Thêm tham chiếu ..." → tab "Dự án" → chọn "MyBaseProject". Các thuộc tính của tham chiếu này là giống nhau ngoại trừ các thành viên sau:

  • Sự miêu tả -
  • Đường dẫn - D: \ webs \ CMS \ MyBaseProject \ bin \ Debug \ MyBaseProject.dll
  • Phiên bản - 1.0.0.0

Nếu tôi chạy bản dựng trong Visual Studio , tệp elmah.dll được sao chép vào thư mục bin của MyWebProject1 , cùng với MyBaseProject.dll!

Tuy nhiên, nếu tôi dọn dẹp và chạy MSBuild cho giải pháp (thông qua D: \ webs \ CMS> C: \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ MSBuild.exe / t: ReBuild / p: Cấu hình = Gỡ lỗi MyProject.sln ) elmah.dll bị thiếu trong thư mục bin của MyWebProject1 - mặc dù bản thân bản dựng không có cảnh báo hoặc lỗi!

Tôi đã chắc chắn rằng .csproj của MyBaseProject chứa phần tử riêng có giá trị "true" (đó phải là bí danh cho " copy local " trong Visual Studio):

<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>

(Theo mặc định, thẻ riêng không xuất hiện trong xml của .csproj, mặc dù Visual Studio đã nói "sao chép cục bộ" đúng. Tôi đã chuyển "sao chép cục bộ" thành sai - đã lưu - và đặt lại thành đúng - lưu lại!)

Có gì sai với MSBuild? Làm cách nào để có được tham chiếu (elmah.dll) được sao chép vào thùng của MyWebProject1?

Tôi KHÔNG muốn thêm một hành động sao chép postbuild vào mỗi lệnh postbuild của dự án! (Hãy tưởng tượng tôi sẽ có nhiều dự án phụ thuộc vào MyBaseProject!)


11
Tôi muốn nhận được một câu trả lời rõ ràng hơn cho lý do tại sao điều này xảy ra.
David Faivre

1
Hãy xem câu trả lời được cung cấp ở đây
Anuroopa Shenoy

1
bất kỳ giải pháp cuối cùng với mẫu mã nguồn đầy đủ làm việc về nó?
Kiquenet

2
Xem câu trả lời stackoverflow.com/a/21055664/21579 dưới đây bởi @deadlydog. Giải thích tuyệt vời và giải quyết vấn đề cho tôi ... câu trả lời được bình chọn nhiều nhất dưới đây là không chính xác cho VS2012.
Jeff Widmer

Câu trả lời:


153

Tôi không chắc tại sao nó lại khác khi xây dựng giữa Visual Studio và MsBuild, nhưng đây là những gì tôi đã tìm thấy khi gặp phải vấn đề này trong MsBuild và Visual Studio.

Giải trình

Đối với kịch bản mẫu, giả sử chúng ta có dự án X, lắp ráp A và lắp ráp B. Lắp ráp tham chiếu A lắp ráp B, vì vậy dự án X bao gồm một tham chiếu đến cả A và B. Ngoài ra, dự án X bao gồm mã tham chiếu lắp ráp A (ví dụ A. Một số chức năng ()). Bây giờ, bạn tạo một dự án Y mới tham chiếu dự án X.

Vì vậy, chuỗi phụ thuộc trông như thế này: Y => X => A => B

Visual Studio / MSBuild cố gắng trở nên thông minh và chỉ đưa các tài liệu tham khảo vào dự án Y mà nó phát hiện theo yêu cầu của dự án X; nó làm điều này để tránh ô nhiễm tham chiếu trong dự án Y. Vấn đề là, vì dự án X không thực sự chứa bất kỳ mã nào sử dụng rõ ràng lắp ráp B (ví dụ B.SomeFunction ()), VS / MSBuild không phát hiện ra rằng B là bắt buộc bởi X, và do đó không sao chép nó vào thư mục bin của dự án Y; nó chỉ sao chép các cụm X và A.

Giải pháp

Bạn có hai tùy chọn để giải quyết vấn đề này, cả hai tùy chọn này sẽ dẫn đến việc tập hợp B được sao chép vào thư mục bin của dự án Y:

  1. Thêm một tham chiếu đến lắp ráp B trong dự án Y.
  2. Thêm mã giả vào một tệp trong dự án X sử dụng cụm B.

Cá nhân tôi thích tùy chọn 2 vì một vài lý do.

  1. Nếu bạn thêm một dự án khác trong tương lai tham chiếu dự án X, bạn sẽ không phải nhớ cũng bao gồm một tham chiếu đến cụm B (giống như bạn sẽ phải làm với tùy chọn 1).
  2. Bạn có thể có ý kiến ​​rõ ràng nói rằng tại sao mã giả cần phải ở đó và không loại bỏ nó. Vì vậy, nếu ai đó vô tình xóa mã (nói với công cụ tái cấu trúc tìm mã không sử dụng), bạn có thể dễ dàng thấy từ kiểm soát nguồn rằng mã được yêu cầu và để khôi phục mã. Nếu bạn sử dụng tùy chọn 1 và ai đó sử dụng công cụ tái cấu trúc để dọn sạch các tài liệu tham khảo không sử dụng, bạn không có bất kỳ nhận xét nào; bạn sẽ chỉ thấy rằng một tham chiếu đã bị xóa khỏi tệp .csproj.

Dưới đây là một mẫu "mã giả" mà tôi thường thêm vào khi gặp tình huống này.

    // 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
Điều không được thảo luận ở đây là có sự khác biệt giữa sao chép sản phẩm xây dựng trong / bin của dự án web và sao chép thường quy vào thư mục đầu ra đích (ví dụ / bin / x86 / Gỡ lỗi). Cái trước được thực hiện bởi dự án được tham chiếu khi nó xây dựng và cái sau được thực hiện bởi dự án web phụ thuộc. Kiểm tra Microsoft.Common.target giúp hiểu điều này. Các bản sao vào web / bin hoàn toàn không phụ thuộc vào hành vi sao chép cục bộ - sao chép các tác động cục bộ lên bản sao vào thư mục đích đầu ra không phải là một phần của cấu trúc được tham chiếu bởi Cassini chạy qua Debug.
dùng1164178

6
bạn có thể giải thích lý do tại sao nó đã làm việc với VS KHÔNG CÓ thêm "mã giả" mà không phải với msbuild không?
toebens

3
Thậm chí ít xâm lấn hơn so với việc gọi một hàm, bạn có thể gán loại của một lớp có trong tập hợp cho một biến giả. Type dummyType = typeof(AssemblyA.AnyClass);
Arithmomaniac

14
Giải pháp số 2 như được hiển thị ở trên sẽ hoạt động trừ khi bạn đã cài đặt 'Tối ưu hóa mã' trong Visual Studio. Trong trường hợp đó, nó vẫn sẽ loại trừ dll. Tôi đã thêm một dòng nữa để ghi đè lên "tối ưu hóa" của nó. Console.WriteLine(dummyType.FullName);
JasonG

3
Giải pháp 2 không hoạt động với tôi trong Visual Studio 2017. Lần đầu tiên tôi nghĩ rằng đó là vì, trong bản lắp ráp X của tôi, tôi chỉ sử dụng một enumtừ B và tôi cho rằng enum đã được nội tuyến. Tôi đã thêm mã để sử dụng trực tiếp một loại từ B và điều đó không có ích. Nó luôn luôn là trường hợp X của tôi sử dụng các loại trong A mà các loại lớp con trong B vì vậy tôi không thể hiểu làm thế nào trình biên dịch nghĩ rằng B không được X yêu cầu và có thể bỏ qua. Đây là bonkers.
Xharlie

170

Tôi chỉ đối phó với nó như thế này. Đi đến các thuộc tính của tài liệu tham khảo của bạn và làm điều này:

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

và đó là nó.

Visual Studio 2010 ban đầu không đặt: <private>True</private> trong thẻ tham chiếu và đặt "sao chép cục bộ" thành sai khiến nó tạo thẻ. Sau đó, nó sẽ đặt thành đúng và sai tương ứng.


10
Đây là một ơn trời. Cảm ơn vì điều này!
Rebecca

22
Không hoạt động với tôi với MSBuild 4 / VS2012. Đó là, tôi đã có thể cập nhật các tài liệu tham khảo để nói <Private>true</Private>nhưng dường như nó không có tác dụng gì với MSBuild. Cuối cùng, tôi chỉ thêm các tham chiếu NuGet vào các dự án downlevel.
Michael Teper

2
Không làm việc cho tôi. Nó vẫn không sao chép System.Net.Http.Formatted vào thư mục bin.
Akira Yamamoto

4
Điều này là tương đương với Have you tried turning it off and on again?, và nó đã làm việc!
guanome

6
Có vẻ như VS2015 vẫn hoạt động giống nhau: cài đặt 'Sao chép cục bộ' thành 'Sai' rồi quay lại 'Đúng' trên các tác phẩm được tham chiếu.
lật

38

Nếu bạn không sử dụng lắp ráp trực tiếp trong mã thì Visual Studio trong khi cố gắng hữu ích sẽ phát hiện ra rằng nó không được sử dụng và không bao gồm nó trong đầu ra. Tôi không chắc tại sao bạn lại thấy hành vi khác nhau giữa Visual Studio và MSBuild. Bạn có thể thử đặt đầu ra bản dựng thành chẩn đoán cho cả hai và so sánh kết quả xem nơi nó phân kỳ.

Đối với tham chiếu elmah.dll của bạn nếu bạn không tham chiếu trực tiếp vào mã, bạn có thể thêm nó dưới dạng một mục vào dự án của mình và đặt Build Action thành Contentvà Copy to Output Directory thành Always.


3
+1 cho bản sao của bạn vào nhận xét Thư mục đầu ra, nếu Elmah không được sử dụng trong mã, có nghĩa là sao chép dưới dạng nội dung.
Kit Roed

4
Thật vậy, nó bỏ qua các tập hợp không được sử dụng, NHƯNG một điều quan trọng cần lưu ý, vì VS 2010 sử dụng lắp ráp trong từ điển tài nguyên XAML không được coi là sử dụng assmebly bởi VS, vì vậy nó sẽ không sao chép nó.
Alex Burtsev


Điều này là tốt hơn cho một dự án thử nghiệm đơn vị nơi tôi cần dll. Tôi không muốn thêm một dll rằng dự án chính không cần chỉ để làm cho các thử nghiệm chạy!
Lukos

14

Hãy xem:

Chủ đề diễn đàn MSBuild này tôi đã bắt đầu

Bạn sẽ tìm thấy giải pháp tạm thời / cách giải quyết của tôi ở đó!

(MyBaseProject cần một số mã tham chiếu một số lớp (bất cứ thứ gì) từ elmah.dll cho elmah.dll được sao chép vào thùng của MyWebProject1!)


1
Chết tiệt - đây là giải pháp duy nhất tôi đã từng đến - hy vọng có thể có một cách tốt hơn để làm điều đó!
nickspoon

2
Xem phản hồi của andrew bên dưới để biết giải pháp ít hack hơn (không vi phạm!)
MPritchard

1
Đối với những người đang xem xét điều này, câu trả lời của toebens trên MSDN về cơ bản giống như câu trả lời của deadlydog , được cung cấp vài năm sau đó.
jpaugh

8

Tôi đã từng gặp vấn đề tương tự.

Kiểm tra xem phiên bản khung của dự án của bạn có giống với phiên bản khung của dll mà bạn đưa vào tham chiếu không.

Trong trường hợp của tôi, ứng dụng khách của tôi được biên dịch bằng "Khung khách 4" và DLL nằm trong "Khung 4".


6

Vấn đề tôi gặp phải là tôi có một dự án phụ thuộc vào dự án thư viện. Để xây dựng tôi đã làm theo các bước sau:

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

Điều đó tất nhiên có nghĩa là tôi đã thiếu các tệp dll của thư viện trong thùng và quan trọng nhất là trong tệp zip gói. Tôi thấy điều này hoạt động hoàn hảo:

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

Tôi không biết tại sao điều này hoạt động hoặc tại sao nó không ở nơi đầu tiên. Nhưng hy vọng rằng sẽ giúp.


Tôi đã có cùng một vấn đề xây dựng toàn bộ giải pháp bằng cách sử dụng / t: Xây dựng từ TeamCity trong một bước sau đó trong / t: Gói tiếp theo trên dự án WebAPI. Bất kỳ dlls được tham chiếu bởi bất kỳ tài liệu tham khảo dự án đã không được bao gồm. Điều này đã được sửa bằng cách sử dụng gói trên - / T: Rebuild; Gói trên WebAPI sau đó bao gồm các dll đó.
Andy Hoyle

5

Tôi chỉ có cùng một vấn đề và hóa ra là do 2 dự án trong cùng một giải pháp đã tham chiếu một phiên bản khác của thư viện bên thứ 3.

Khi tôi sửa tất cả các tài liệu tham khảo, mọi thứ đều hoạt động hoàn hảo.


4

Như Alex Burtsev đã đề cập trong một bình luận, bất cứ điều gì chỉ được sử dụng trong từ điển tài nguyên XAML, hoặc trong trường hợp của tôi, bất cứ thứ gì chỉ được sử dụng trong XAML và không có mã phía sau, đều không được MSBuild coi là 'sử dụng'.

Vì vậy, chỉ cần tạo một tham chiếu giả cho một lớp / thành phần trong hội đồng trong một số mã phía sau là đủ thuyết phục MSBuild rằng hội thảo thực sự được sử dụng.


Đây chính xác là vấn đề của tôi và giải pháp hiệu quả. Đã dành quá lâu để cố gắng để tìm ra điều này. Cảm ơn Scott & @Alex Burstev
karol

Thật đau buồn, điều này đã khiến tôi phát điên. , tôi đã sử dụng FontAwgie.WPF và chỉ từ trong XAML (vì lý do rõ ràng). Thêm một phương pháp giả giúp. Cảm ơn! Và vâng, VS 2017 15.6 vẫn bị ảnh hưởng, vì vậy tôi đã gửi một lỗi: github.com/dotnet/roslyn/issues/25349
Sören Kuklau

3

Việc thay đổi khung mục tiêu từ .NET Framework 4 Client Profile sang .NET Framework 4 đã khắc phục vấn đề này cho tôi.

Vì vậy, trong ví dụ của bạn: đặt khung mục tiêu trên MyWebProject1 thành .NET Framework 4


3

Sử dụng sơ đồ của deadlydog,

Y => X => A => B ,

vấn đề của tôi là khi tôi xây dựng Y, các hội đồng (A và B, tất cả 15 người trong số họ) từ X không hiển thị trong thư mục bin của Y.

Tôi đã giải quyết nó bằng cách xóa tham chiếu X khỏi Y, lưu, xây dựng, sau đó thêm lại tham chiếu X (tham chiếu dự án) và lưu, xây dựng và A và B bắt đầu hiển thị trong thư mục bin của Y.


Sau nhiều giờ tìm kiếm và thử nhiều giải pháp khác, giải pháp này hiệu quả với tôi.
Suncat2000 ngày

2

Tôi đã có cùng một vấn đề và dll là một tài liệu tham khảo được tải động. Để giải quyết vấn đề tôi đã thêm một "cách sử dụng" với không gian tên của dll. Bây giờ dll được sao chép trong thư mục đầu ra.



2

Tham chiếu các hội đồng không được sử dụng trong quá trình xây dựng không phải là thực hành chính xác. Bạn nên tăng tệp xây dựng của mình để nó sẽ sao chép các tệp bổ sung. Hoặc bằng cách sử dụng một sự kiện xây dựng bài hoặc bằng cách cập nhật nhóm tài sản.

Một số ví dụ có thể được tìm thấy trong bài viết khác


2

Một kịch bản khác mà điều này xuất hiện là nếu bạn đang sử dụng loại dự án "Trang web" cũ hơn trong Visual Studio. Đối với loại dự án đó, không thể tham chiếu các tệp nằm ngoài cấu trúc thư mục riêng của nó (thư mục hiện tại trở xuống). Vì vậy, trong câu trả lời ở trên, giả sử cấu trúc thư mục của bạn trông như thế này:

nhập mô tả hình ảnh ở đây

Trong đó ProjectX và ProjectY là thư mục mẹ / con và tham chiếu ProjectX A.dll lần lượt tham chiếu B.dll và B.dll nằm ngoài cấu trúc thư mục, chẳng hạn như trong gói Nuget trên thư mục gốc (Gói), sau đó A. dll sẽ được bao gồm, nhưng B.dll thì không.


0

Tôi đã có một vấn đề tương tự ngày hôm nay, và đây chắc chắn không phải là câu trả lời cho câu hỏi của bạn. Nhưng tôi muốn thông báo cho tất cả mọi người, và có thể cung cấp một tia sáng sâu sắc.

Tôi có một ứng dụng ASP.NET. Quá trình xây dựng được thiết lập để làm sạch và sau đó xây dựng.

Tôi có hai kịch bản CI của Jenkins . Một cho sản xuất và một cho dàn dựng. Tôi đã triển khai ứng dụng của mình để dàn dựng và mọi thứ đều hoạt động tốt. Đã triển khai để sản xuất và thiếu một tệp DLL được tham chiếu. Tệp DLL này chỉ là trong thư mục gốc của dự án. Không có trong bất kỳ kho lưu trữ NuGet. DLL đã được đặt thành .do not copy

Kịch bản CI và ứng dụng giống nhau giữa hai lần triển khai. Vẫn sau khi dọn dẹp và triển khai trong môi trường dàn dựng, tệp DLL đã được thay thế trong vị trí triển khai của ứng dụng ASP.NET ( bin/). Đây không phải là trường hợp cho môi trường sản xuất.

Hóa ra trong một nhánh thử nghiệm tôi đã thêm một bước vào quy trình xây dựng để sao chép tệp DLL này vào binthư mục. Bây giờ phần đó mất một chút thời gian để tìm ra. Quá trình CI không tự làm sạch. DLL bị bỏ lại trong thư mục làm việc và đang vô tình được đóng gói với tệp ASP.NET .zip. Nhánh sản xuất không bao giờ có tệp DLL được sao chép theo cùng một cách và không bao giờ vô tình triển khai điều này.

TLDR; Kiểm tra và đảm bảo bạn biết máy chủ xây dựng của bạn đang làm gì.


0

Đảm bảo rằng cả hai dự án đều trong cùng một phiên bản .net cũng kiểm tra sao chép thuộc tính cục bộ nhưng điều này phải truelà mặc định


0

Sử dụng Visual Studio 2015 thêm tham số bổ sung

/ execonbuild = false

đến dòng lệnh msbuild đã khắc phục sự cố.


-1

Tôi chỉ gặp phải một vấn đề rất giống nhau. Khi biên dịch bằng Visual Studio 2010, tệp DLL đã được bao gồm trongbin thư mục. Nhưng khi biên dịch bằng MSBuild, tệp DLL của bên thứ ba không được bao gồm.

Rất bực bội. Cách tôi giải quyết là đưa tham chiếu NuGet vào gói trong dự án web của tôi mặc dù tôi không sử dụng trực tiếp ở đó.


Đây là một bản sao của câu trả lời hàng đầu.
Giles Roberts

-3

Bao gồm tất cả các tệp DLL được tham chiếu từ các dự án của bạn trong dự án Trang web không phải lúc nào cũng là một ý tưởng hay, đặc biệt là khi bạn đang sử dụng nội xạ phụ thuộc : dự án web của bạn chỉ muốn thêm một tham chiếu đến tệp / dự án DLL giao diện, chứ không phải bất kỳ DLL triển khai cụ thể nào tập tin.

Bởi vì nếu bạn thêm một tham chiếu trực tiếp vào tệp / dự án DLL thực hiện, bạn không thể ngăn nhà phát triển của mình gọi "mới" trên các lớp cụ thể của tệp / dự án DLL thực hiện thay vì qua giao diện. Bạn cũng đã nêu "mã cứng" trong trang web của mình để sử dụng triển khai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.