NuGet能否在同一解决方案中使用每个项目的包下载路径?

5
考虑我们解决方案的版本库/文件结构...
Shared Repo (Checked out to D:/Shared/trunk)
    ├───Shared1.dll Project
    └───Shared2.dll Project

App1 Repo (Checked out to C:/Code/App1/Trunk)
    ├───App1 Project (Refs Shared1.dll project)
    ├───App1.dll Project (Refs Shared1.dll and Shared2.dll projects)
    └───App1.sln

App2 Repo (Checked out to C:/Code/App2/Trunk)
    ├───App2 Project (Refs Shared1.dll project)
    ├───App2a.dll Project (Refs Shared1.dll and Shared2.dll projects)
    ├───App2b.dll Project (Refs Shared1.dll and App2a.dll projects)
    └───App2.sln

为了更方便地处理代码,我们直接将共享项目引入应用程序的解决方案中。例如,如果您打开App1.sln,那么这将是您的项目树...
App1.sln
    ├───Shared1.dll Project
    ├───Shared2.dll Project
    ├───App1 Project (Refs Shared1.dll project)
    └───App1.dll Project (Refs Shared1.dll and Shared2.dll projects)

正如您所看到的,这两个共享的 DLL 来自一个单独的代码库,但包含在此解决方案中。Visual Studio 可以毫无问题地处理这一点,当您对解决方案执行提交操作时,会提示您正在更新多个存储库。这很好,并且正是我们想要的。
然而,我们遇到的问题与 NuGet 有关。据我们了解,NuGet.config(以及其读取/应用的层次结构/优先级)相对于解决方案文件,因此项目的 NuGet 引用会相应地更新。这会导致问题,因为 Shared1.dll 和 Shared2.dll 中的 NuGet 包引用是相对于 App1.sln 的,当您在 App1.sln 中工作时,意味着如果其他人在 App2.sln 中工作,并且他们没有以与您完全相同的方式检出两个源代码库,则引用将会断开。
我们的解决方法是始终将所有三个源代码库作为兄弟姐妹放在同一个文件夹中进行检出,然后将打包文件夹作为另一个兄弟姐妹放在同一级别下,在 NuGet.config 旁边添加 '../packages'。这可以确保引用永远不会中断,但会强制确定检出的位置,这可能会成为问题。
C:/Code/
    ├───Shared Trunk
    ├───App1 Trunk
    ├───App2 Trunk
    └───packages

然而,如果我们能够指定每个项目的软件包下载位置,我们就可以将打包文件夹相对于项目本身放置,这意味着无论您将它们检出到哪里,它们都会始终找到所需的软件包。是的,在我们的示例中,这意味着会有重复的软件包下载,但磁盘空间不是问题。代码的维护才是重点。
C:/Code/
    ├───Shared Trunk
    │    └─sharedpackages
    ├───App1 Trunk
    │    └─app1packages
    └───App2 Trunk
         └─app2packages

我们需要的是,当打开App1.sln时,我们希望Shared1.dll和Shared2.dll的包放在'sharedpackages'文件夹中,但是App1和App1.dll使用的包放在app1packages中。

那么...这种情况是否可能?您能否指定每个项目的不同NuGet包下载路径,而不管它们在哪个解决方案中?


1
正如你所怀疑的那样,这是不可能的。NuGet目前始终会相对于解决方案目录检查NuGet.Config文件。因此,像你所做的那样将不同的存储库检出到指定的相对目录可能是唯一的解决方案。 - Matt Ward
如果您为共享项目创建解决方案,则所有项目都将引用其父文件夹中的“packages”文件夹。然后,您可以合并应用程序和共享项目,并且它们都将使用正确的相对引用。 - Kiliman
我最初也考虑过这个问题,但是当你把它们带回一个解决方案中(例如App1),NuGet就会完全混乱,不知道从哪里获取东西。更新也无法正常工作。 - Mark A. Donohoe
我正在使用SVN。除了上面提到的内容,我不知道还有什么需要补充的。要复制这个问题最简单的方法是在您现有的repo中创建三个子文件夹,但然后将它们分别检出到您磁盘上的三个单独的文件夹中(因此您必须逐个检入它们)。它们实际上共享同一个repo的事实是无关紧要的。将其中两个作为兄弟姐妹检出,但将第三个放在层次结构中更高或更低的位置。然后在其中一个兄弟文件夹中放置一个DLL项目,并在其他两个中引用该DLL项目的应用程序项目。这将显示出问题所在。 - Mark A. Donohoe
1
这根本行不通,因为整个目的是要访问源代码,以便您可以同时处理DLL和应用程序。看一下顶部的App1.sln的结构。它引用了DLL的项目,而不是DLL本身。明白了吗? - Mark A. Donohoe
显示剩余2条评论
2个回答

1

我和 /u/MarquelV 处于同样的情况。

根据我对 nuget 提供的选项(至少到 ver. 3.5)的调查,我得出结论,需要完全忽略 Visual Studio 中 nuget 的图形工具(至少在安装/恢复包方面),并禁用自动包恢复(工具 -> 选项 -> Nuget 等)。然后,每当需要安装/恢复包时,通过命令行调用 nuget.exe,并指定应将包放置的文件夹 - 这一点很重要,因为 Visual Studio 中的 nuget 图形界面通常会将包存储在“全局”存储库中(通常就在解决方案的 .sln 文件旁边)。

在我的项目中,我会在每个项目中创建一个 .nuget 文件夹,并配备 nuget.exe,并以此方式引用 dll。

最后,每个项目都需要通过 .csproj 使用 nuget 进行包恢复,如下所示:

 <Target Name="BeforeBuild">
      <Exec Command=".\.nuget\nuget.exe restore  .\packages.config -PackagesDirectory .\packages"/>
 </Target>

这其中需要注意的是,Nuget的图形化工具和自动包恢复功能(工具 -> 选项 -> Nuget)不能保证实现所述目标。

我喜欢你的“BeforeBuild”解决方案。正如你所说,它并不完全符合我的期望,因为现在不能使用图形工具,所以无法通过命令行修改包,但是仍然有些用处,所以我会将其标记为答案。(而且现在它也太老了。 :) - Mark A. Donohoe

0

我最近遇到了一个类似的问题。在我的情况下,我将较小的解决方案中的项目合并到了一个更大的解决方案中。这些项目仍然引用其子文件夹中的包,而我不想改变这些引用并破坏较小的解决方案。我通过将项目包路径符号链接到解决方案级别的路径来解决了这个问题。

mklink /J .\packages ..\packages

这实际上是欺骗项目,让它认为自己正在使用一个更本地的版本的包,而实际上它使用的是更大解决方案中的包。

虽然不完全相同,但足够接近,希望能对某人有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接