簡體   English   中英

類庫中的引用不會復制到正在運行的項目bin文件夾中

[英]References from class library are not copied to running project bin folder

我有一個代表我的邏輯層的類庫。 對於那個庫我已經為Google.Apis.Analytics.v3添加了一個nuget包 - 它安裝了包及其所有依賴項。

我有一個控制台應用程序,它使用該邏輯類庫(常規引用)。 一切都寫得很好。

問題是在運行時它拋出了一個異常,即找不到Google.Apis.dll。 此DLL是與nuget一起下載的依賴項。

檢查BIN文件夾,我發現在類庫bin文件夾中存在此DLL,但在控制台應用程序BIN文件夾中它不存在(而其他相關的DLL是)。 所以這意味着編譯期間復制的並非所有引用。

我在網上搜索過,找到了所有不起作用的解決方法(比如手動編輯項目文件並刪除該dll定義中的真正xml行)。

我最終做的是將相同的nuget庫添加到我的控制台應用程序 - 它可以工作,但感覺有點臟,而不是應該的方式。 我認為控制台應用程序是客戶誰應該從該邏輯類庫獲得它的服務,應該知道它的東西沒有“客戶”擔心它。

此外,該控制台應用程序並不是唯一一個將使用該服務的人,我也計划使用該功能的網絡應用程序 - 所以我需要將相同的nuget添加到該Web應用程序中 - 再次,感覺有點亂......

只有我嗎? 這是正確的方法嗎? 我正在考慮編寫一個WCF項目來處理這個功能 - 但這似乎只是在功能方面的一些開銷,並且可能會減慢我的工作流程,以便在我看來保持“更清潔”。

我只是過度思考嗎?

謝謝

說明

對於示例場景,假設我們有項目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. 將虛擬代碼添加到項目X中使用程序集B的文件中。

我個人更喜歡選項2,原因有兩個。

  1. 如果您將來添加另一個引用項目X的項目,則不必記住還包括對程序集B的引用(就像您必須使用選項1一樣)。
  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);
    }

如果您有以下依賴關系鏈:Lib1 < - Lib2 < - MyApp

TLDR版本:通過不做出假設,構建系統避免引入不確定性/意外行為。

構建MyApp時,Lib2將被復制到MyApp的bin目錄中,但Lib1不會。 您需要在MyApp中添加對Lib2 Lib1的引用,以便在MyApp的bin目錄中獲取Lib1的dll(否則您將收到運行時錯誤)。 確定最終存放在Lib2的bin目錄中的確切文件集是不可能的(或者可能只是非常困難),這些文件安全且適合復制到MyApp。 如果構建系統假設Lib2的bin目錄中的所有內容對MyApp都是安全的,或者它為您隱式引用了Lib1,則可能會無意中更改MyApp的行為。

想象一個解決方案,其中多個項目依賴於Lib2,但其中一個項目想要使用Assembly.LoadFrom / Activator.CreateInstance / MEF / etc加載相鄰的.dll文件。 (一個插件)而另一個沒有。 自動復制操作可以將Lib2與插件dll一起抓取並將其復制到第一個和第二個項目的構建目錄(因為它是由於構建操作而在Lib2的bin目錄中)。 這將改變第二個應用程序的行為。

或者,如果它更聰明,並且在您引用Lib2時隱式引用了Lib1(並且不僅僅復制bin目錄內容),它仍然可能導致意外后果。 如果MyApp已經依賴於Lib1,但它使用的是與Lib2所需的版本兼容的GAC / ngen副本,該怎么辦? 如果添加對Lib2的引用隱式為您創建了對Lib1的引用,則可能會更改加載了哪個Lib1並更改應用程序的運行時行為。 它可能會檢測到MyApp的bin目錄中已經有一個Lib1並跳過它,但是它會假設已經存在的Lib1是正確的。 也許它是一個陳舊的.dll等待被Clean操作擦掉而且覆蓋是正確的舉動。

NuGet解決了您使用包依賴性描述的問題。 如果Lib1和Lib2都有nuget包並且Lib2包依賴於Lib1包,當你將Lib2添加到MyApp時,也會添加Lib1。 兩個pacakges的dll最終都會進入MyApp的bin目錄。

最好的辦法是反思你的想法。 而不是思考:

  • Lib2需要引用Lib1才能編譯,所以我將添加對Lib1的引用

認為:

  • MyApp需要Lib2。 無論Lib2需要什么,我都需要。 所以MyApp和Lib2都得到了對Lib1的引用。

如果您有10個dll,則更容易使用postbuild事件進行復制:

xcopy "$(ProjectDir)bin\*.dll" $(SolutionDir)MyTargetProject\bin\" /y

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM