ChatGPT解决这个技术问题 Extra ChatGPT

当某些项目包含在多个解决方案中时,为所有解决方案设置一个通用的 nuget 包文件夹

我一直在使用 NuGet 从外部和内部包源中检索包,非常方便。但是我已经意识到这些包默认存储在每个解决方案中,当一些具有 NuGet 引用的项目包含在多个解决方案中时,这是非常令人沮丧的。然后将引用更改为其他解决方案包文件夹,其他开发人员或构建机器实际上可能无法使用该文件夹。

我已经看到,在 NuGet 2.1 版本中,有一些方法可以指出一个公共包位置(可能在项目根级别,我们使用 TFS 源代码控制),请参阅 release notes 。我正在使用 NuGet v2.7

但是我尝试添加 nuget.config 文件而没有看到任何效果。包仍存储在解决方案文件夹中。有什么我错过的吗?似乎有不同的 xml 节点结构要添加到 nuget.config 文件中,具体取决于回答该问题的人:Schwarzie 在 another Stackoverflow thread 上建议:

<settings>
  <repositoryPath>..\..\[relative or absolute path]</repositoryPath>
</settings>

NuGet 2.1 的发行说明(请参阅上面的链接)建议采用以下格式:

<configuration>
  <config>
    <add key="repositoryPath" value="..\..\[relative or absolute path]" />
  </config>
</configuration>

我不知道其中哪一个,或任何一个,或两者最终会起作用。我在解决方案级别都尝试过。 nuget.config 文件可以放在 TFS 项目根级别,还是必须放在解决方案目录中?似乎 NuGet 以特定顺序从这些文件中读取和应用设置,为什么将它们添加到多个级别是有意义的,其中解决方案级别的 nuget.config 文件将覆盖 TFS 项目根级别的文件。这可以澄清吗?

我是否需要删除所有已安装的软件包才能使这些引用生效?如果有人可以提供从特定于解决方案的 nuget 使用移动到公共包文件夹的分步说明,我会很高兴,属于多个解决方案的项目可以在该文件夹中找到所需的 nuget 包。

我怀疑对您的问题的简短回答(隐藏在下面 Vermis 的回答中)是您缺少相对路径前面的 $。此外,关于 NuGet.Config 文件的问题的答案是 here。它首先在 .nuget 中查找,然后在所有父目录中查找,然后在 AppData 中的“全局”文件中查找:然后以 REVERSE 顺序应用它们(无论 that 是什么意思)。
这似乎很难。有一个名为 Paket 的工具可以解决这个问题:fsprojects.github.io/Paket
迟到的评论。只是想补充一点,如果在开始此更改时运行 Visual Studio,则需要重新启动它,因为 nuget.config 文件似乎在 VS 启动期间被读取。此外,没有 $ 也没有问题,只是不要以反斜杠开头。

C
Community

我对外部和内部包源也有类似的情况,并且在多个解决方案中引用了项目。我今天刚刚使用我们的代码库之一,它似乎正在与开发人员工作站和我们的构建服务器一起使用。下面的过程考虑到了这种情况(尽管在其他地方有通用包文件夹应该不难适应)。

代码库 项目 A 项目 B 项目 C 解决方案 解决方案 1 解决方案 2 解决方案 3 包(这是所有解决方案共有的一个)

项目A

项目 B

项目 C

解决方案 解决方案 1 解决方案 2 解决方案 3 包(这是所有解决方案共有的一个)

解决方案 1

解决方案 2

解决方案 3

包(这是所有解决方案共享的通用包)

使用 Visual Studio 2015 Update 3 从 NuGet 3.5.0.1484 更新答案

这个过程现在比我最初解决这个问题并认为是时候更新它时要容易一些。一般来说,过程是相同的,只是步骤更少。结果是一个解决或提供以下问题的过程:

需要提交到源代码控制的所有内容在解决方案中都是可见和跟踪的

使用 Visual Studio 中的包管理器安装新包或更新包将使用正确的存储库路径

初始配置后,不会对 .csproj 文件进行黑客攻击

无需修改开发人员工作站(代码已在签出时构建)

有一些潜在的缺点需要注意(我还没有经历过,YMMV)。请参阅下面的 Benol's 答案和评论。

添加 NuGet.Config

您需要在 \Solutions\ 文件夹的根目录中创建一个 NuGet.Config 文件。确保这是您创建的 UTF-8 编码文件,如果您不确定如何执行此操作,请使用 Visual Studio 的 File->New->File 菜单,然后选择 XML File 模板。将以下内容添加到 NuGet.Config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>  
  <config>
    <add key="repositoryPath" value="$\..\Packages" />
  </config>
</configuration>

对于 repositoryPath 设置,您可以使用 $ 标记指定绝对路径或相对路径(推荐)。 $ 标记基于 NuGet.Config 所在的位置($ 标记实际上相对于 NuGet.Config 位置的下一级)。所以,如果我有 \Solutions\NuGet.Config 并且我想要 \Solutions\Packages 我需要指定 $\..\Packages 作为值。

接下来,您需要向您的解决方案添加一个名为“NuGet”的解决方案文件夹(右键单击您的解决方案,添加-> 新建解决方案文件夹)。解决方案文件夹是仅存在于 Visual Studio 解决方案中的虚拟文件夹,不会在驱动器上创建实际文件夹(您可以从任何地方引用文件)。右键单击“NuGet”解决方案文件夹,然后添加-> 现有项目并选择 \Solutions\NuGet.Config。

我们这样做的原因是它在解决方案中是可见的,并且应该有助于确保它正确地提交给您的源代码控制。您可能希望对代码库中参与共享项目的每个解决方案执行此步骤。

通过将 NuGet.Config 文件放在任何 .sln 文件上方的 \Solutions\ 中,我们利用了 NuGet 将从“当前工作目录”递归地向上导航文件夹结构以查找要使用的 NuGet.Config 文件这一事实。 “当前工作目录”在这里意味着几个不同的东西,一个是 NuGet.exe 的执行路径,另一个是 .sln 文件的位置。

切换你的包文件夹

首先,我强烈建议您浏览每个解决方案文件夹并删除所有存在的 \Packages\ 文件夹(您需要先关闭 Visual Studio)。这样可以更轻松地查看 NuGet 将新配置的 \Packages\ 文件夹放在哪里,并确保指向错误 \Packages\ 文件夹的任何链接都将失败,然后可以修复。

在 Visual Studio 中打开您的解决方案并启动 Rebuild All。忽略您将收到的所有构建错误,此时这是预期的。但是,这应该会在构建过程开始时启动 NuGet 包还原功能。验证您的 \Solutions\Packages\ 文件夹是否已在您想要的位置创建。如果没有,请检查您的配置。

现在,对于解决方案中的每个项目,您都需要:

右键单击项目并选择 Unload Project 右键单击项目并选择 Edit your-xxx.csproj 找到对 \packages\ 的任何引用并将它们更新到新位置。其中大部分将是 引用,但不是全部。例如,WebGrease 和 Microsoft.Bcl.Build 将具有需要更新的单独路径设置。保存 .csproj 然后右键单击项目并选择重新加载项目

更新完所有 .csproj 文件后,启动另一个 Rebuild All,您应该不会再遇到有关缺少引用的构建错误。此时您已完成,现在已将 NuGet 配置为使用共享的 Packages 文件夹。

从带有 VStudio 2012 的 NuGet 2.7.1 (2.7.40906.75) 开始

首先要记住的是,nuget.config 并不控制 nuget 包系统中的所有路径设置。这特别令人困惑。具体来说,问题在于 msbuild 和 Visual Studio(调用 msbuild)不使用 nuget.config 中的路径,而是在 nuget.targets 文件中覆盖它。

环境准备

首先,我将浏览您的解决方案的文件夹并删除所有存在的 \packages\ 文件夹。这将有助于确保所有软件包都明显安装到正确的文件夹中,并有助于发现整个解决方案中的任何错误路径引用。接下来,我会确保你安装了最新的 nuget Visual Studio 扩展。我还会确保您在每个解决方案中都安装了最新的 nuget.exe。打开命令提示符并进入每个 $(SolutionDir)\ .nuget\ 文件夹并执行以下命令:

nuget update -self

为 NuGet 设置通用包文件夹路径

打开每个 $(SolutionDir)\ .nuget\NuGet.Config 并在 部分中添加以下内容:

<config>
    <add key="repositorypath" value="$\..\..\..\Packages" />
</config>

注意:您可以使用绝对路径或相对路径。请记住,如果您使用带有 $ 的相对路径,它相对于 NuGet.Config 位置的下一级(相信这是一个错误)。

为 MSBuild 和 Visual Studio 设置通用包文件夹路径

打开每个 $(SolutionDir)\.nuget\NuGet.targets 并修改以下部分(请注意,对于非 Windows,它下面还有另一个部分):

<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
    <!-- Windows specific commands -->
    <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
    <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
    <PackagesDir>$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
</PropertyGroup>

将 PackagesDir 更新为

<PackagesDir>$([System.IO.Path]::GetFullPath("$(SolutionDir)\..\Packages"))</PackagesDir>

注意:GetFullPath 会将我们的相对路径解析为绝对路径。

将所有 nuget 包恢复到公用文件夹中

打开命令提示符并转到每个 $(SolutionDir)\ .nuget 并执行以下命令:

nuget restore ..\YourSolution.sln

此时,您应该在公共位置有一个 \packages\ 文件夹,而在任何解决方案文件夹中都没有。如果没有,请验证您的路径。

修复项目引用

在文本编辑器中打开每个 .csproj 文件,找到对 \packages 的任何引用并将它们更新到正确的路径。其中大部分将是 引用,但不是全部。例如,WebGrease 和 Microsoft.Bcl.Build 将具有需要更新的单独路径设置。

构建您的解决方案

在 Visual Studio 中打开您的解决方案并开始构建。如果它抱怨缺少需要恢复的包,不要假设包丢失并且需要恢复(错误可能会产生误导)。它可能是您的 .csproj 文件之一中的错误路径。在恢复包之前先检查一下。

有关于缺少软件包的构建错误?

如果您已经验证 .csproj 文件中的路径是正确的,那么您有两个选项可以尝试。如果这是从源代码控制更新代码的结果,那么您可以尝试检查一个干净的副本,然后构建它。这适用于我们的一位开发人员,我认为 .suo 文件或类似文件中有一个工件。另一种选择是使用相关解决方案的 .nuget 文件夹中的命令行手动强制执行包还原:

nuget restore ..\YourSolution.sln

感谢您对我的冗长问题的冗长回答。我将尝试此解决方案并回复您。
将两个 .sln 放在同一个目录中会起作用吗?他们最终会共享同一个包目录吗?
我认为这个答案表明了 nuget 的刚性。必须创建如此复杂、刚性的结构来实现这样一个简单的概念:-“在解决方案之间共享相同的组件”表明整个事物的设计不佳。
修复 HintPaths 的方法也有效 - 根据您的喜好更新 NuGet.config 后,在 Package-Manager 控制台中运行“Update-Package -reinstall”。这将重新安装所有软件包,同时修复它们的提示路径。在此之后 - 你可能会留下一些遗物(我在一些 silverlight 项目中 - 目标/构建的“旧”进口仍然存在)
@Vermis 如果我为所有解决方案设置通用 nuget 包文件夹。这对我的 Azure Devops 构建有什么影响?
A
Adam Wyżgoł

除了为所有项目设置通用包位置之外,还可以在项目中更改 HintPath,如下所示:

<HintPath>$(SolutionDir)\packages\EntityFramework.6.1.0\lib\net40\EntityFramework.dll</HintPath>

在大多数情况下,共享项目中只有几个包,因此您可以轻松更改它。

我认为这是更好的解决方案,当您分支代码时,设置公共仓库时,您必须更改相对路径,在此解决方案中您不需要这样做。


亚当是正确的。这是一个令人难以置信的愚蠢问题的最简单的解决方案。
这是一个绝妙的解决方案。简单明了,不需要重建任何代码的结构。
AFAIK $(SolutionDir) 仅在通过 VS 完成构建时设置。所以不要直接通过 msbuild.exe 构建,除非你设置 /p:SolutionDir=path
这可以在这里自动设置 %APPDATA%\Roaming\NuGet\NuGet.Config
在您更新包并用新的相对路径覆盖 HintPath 之前,这非常有效。在包含大量软件包的大型解决方案中变得相当乏味。上帝禁止你必须运行更新包 - 重新安装......
B
Benjol

我尝试使用最新版本的 NuGet (2.7) 和 VS2012 的经验:

删除 .nuget 文件夹(在磁盘上和解决方案中)

将 NuGet.Config 文件放在所有解决方案的公共父文件夹中

删除任何现有的包文件夹

浏览所有 csproj 文件并更改 HintPaths 以指向新位置

利润

就我而言,我想将所有包放在 .packages 中,所以我的 NuGet.Config 如下所示。

 <?xml version="1.0" encoding="utf-8"?>
 <configuration>
   <config>
     <add key="repositorypath" value=".packages" />
   </config>
 </configuration>

请注意,可能会发生一些“奇怪”的事情,但我认为它们是可以忍受的:

如果你从一个解决方案“更新”一个包,它会立即从你的包文件夹中删除旧版本(它不知道你是否有另一个解决方案指向那里)。这并没有让我很困扰,因为其他解决方案只会在需要时恢复。

如果您尝试从右键单击解决方案添加包,如果该包已经存在于另一个解决方案中,它将看到它在那里并显示“绿色勾号”而不是“安装”按钮。我通常从右键单击项目安装,所以这根本不会打扰我。

免责声明:我今天刚刚尝试过,我没有任何长期经验来支持它!


这是推荐的方法。在接受的答案中进行 nuget 恢复的旧 msbuild 集成方法是皮塔饼,我可以确认将 NuGet.config 与 sln 放在一起使用自动包恢复对我们有用。把它放在一个共同的父目录中,我无法确认。
如何将 NuGet.Config 放在所有解决方案(在 TFS 中)的公共父文件夹中,以便他们可以参考?我知道的唯一方法是每个具有文件 nuget.config 的解决方案下的 .nuget 文件夹;如果“repositorypath value=.packages”,那么它会在 .nuget 下创建一个子文件夹,例如:C:\TFS\Comp\Ent\SolABC\.nuget\.packages - 这并不能以干净的方式解决嵌套项目/解决方案这也应该适用于自动 TFS 构建。接受的答案需要一些手工编码的工作,加上“repositorypath value=$\..\..\..\Packages 如果嵌套项目具有不同的相对路径,这将不起作用。
适用于 Visual Studio 2015 和 Nuget 3.4.3
它不仅会立即删除旧包,还会覆盖并破坏您手动编码到 csproj 文件中的 HintPath。 @hB0 是正确的。这仅适用于相对简单的解决方案。一旦你进入一个包含分支、共享项目等的复杂 TFS 工作空间结构,它就无法有效地扩展。
K
Korayem

我有 VS 2013 的 NuGet 版本 2.8.50926。您不需要使用多个 nuget.config 文件,或使用复杂的目录结构。只需修改位于此处的默认文件:

%APPDATA%\Roaming\NuGet\NuGet.Config

这是我的文件的内容:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="repositoryPath" value="C:\Projects\nugetpackages" />
  </config>
  <activePackageSource>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </activePackageSource>
</configuration>

因此,无论解决方案在哪里,所有包都会转到“C:\Projects\nugetpackages”文件夹。

在您的所有解决方案中,只需删除现有的“包”文件夹。然后构建您的解决方案,NuGet 将自动在您指定的新集中目录中恢复丢失的包。


这是迄今为止最简单的解决方案,值得更多的爱!
这确实是今天最简单的解决方案,但您的答案中缺少一件事。您仍然需要在每个项目的 csproj 文件中处理 HintPath。它们不会自动定位到新路径。我对么?
事实上,在我的一些旧项目中,有时会引用“旧”包文件夹。但是对我来说一切正常,所以我猜全局设置优先。
对于 OSX,请参阅 docs.microsoft.com/en-us/nuget/consume-packages/…。我也喜欢下面的 mklink 想法。
C
Christian

已经不需要修改 nuget.targets。它已在 nuget 2.8 (http://nuget.codeplex.com/workitem/2921) 中修复。您只需要设置存储库路径。


J
Janusz Nowak

从 Visual Studio 2013 Update 4 和 Nugget Package Manager 版本 > 2.8.5...

在存储库的根目录中创建 nuget.config 文件。

文件内容:

<configuration>
  <config>
    <add key="repositoryPath" value="packages" />
  </config>
  <packageSources>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
</configuration>

这将导致所有包都将转到您的 nuget.config 文件级别的包文件夹。

现在您可以使用命令“update-package -reinstall”访问每个 .sln nuget 控制台

如果您喜欢同一级别的多个存储库,并且在它们之间共享相同的包文件夹,请尝试使用向上一个文件夹的方式。

 <add key="repositoryPath" value="..\packages" />

但是这种方式会导致 nuget 包引用 csproj 将一个文件夹指向存储库路径之外的一个文件夹。


O
Oleg Tarasov

我编写了一个 NuGet 包,它可以将项目中的所有 NuGet 引用透明地转换为 $(SolutionDir) 相对格式。它使用构建时 XSLT 转换来实现这一点,因此您无需手动破解您的项目文件。你可以自由地更新你的包,它不会破坏任何东西。

https://www.nuget.org/packages/NugetRelativeRefs

或者,如果您使用 Visual Studio 2015 Update 3,则可以将包引用迁移到 project.json 表单,如下所述:https://oren.codes/2016/02/08/project-json-all-the-things


不幸的是,看起来像 Microsoft is moving away from project.json。另外,我喜欢你的 nuget 包。前段时间我使用了NuGetReferenceHintPathRewrite,它做了几乎相同的事情,但方式不同
a
amarnath chatterjee

更新我对 nuget 2.8.3 的体验。这相对简单。所做的一切都是通过右键单击解决方案启用包还原。编辑 NuGet.Config 并添加以下行:

  <config>
    <add key="repositorypath" value="..\Core\Packages" />
  </config>

然后重建解决方案,它将所有包下载到我想要的文件夹并自动更新引用。我对所有其他项目都做了同样的事情,只下载了增量包并引用了现有的包。因此,为所有项目设置了一个公共包存储库。

这是启用包还原的分步过程。

http://blogs.4ward.it/enable-nuget-package-restore-in-visual-studio-and-tfs-2012-rc-to-building-windows-8-metro-apps/


u
user803469

只需将 /packages 硬链接到所需的共享位置。这样您的项目就不会被其他没有特殊包位置的用户破坏。

以管理员身份打开命令提示符并使用

mklink /prefix link_path Target_file/folder_path

g
gravidThoughts

对于任何重要的解决方案,上述答案都将不足。很简单,具有不同相对路径、分支、共享项目等的复杂 TFS 工作区结构使得单个中央存储库成为不可能。

使用 ($SolutionDir) 是朝着正确方向迈出的一步,但是在包含数百个定期更新的包的代码库中,使用 ($SolutionDir) 手动编码 csproj 文件会变得非常乏味(每次更新发生时,HintPath 都会被覆盖一个新的相对路径)。如果您必须运行 Update-Package -Reinstall 会发生什么。

有一个很棒的解决方案,称为 NugetReferenceHintPathRewrite。它在构建之前自动将 ($SolutionDir) 注入到 HintPaths 中(实际上不更改 csproj 文件)。我想它可以很容易地整合到自动化构建系统中


S
Sudhanshu Mishra

使用 NuGet 版本的 VS 2013 专业人士的简短摘要:2.8.60318.667

这是您将包定向到相对于 .nuget 文件夹的路径的方式:

<configuration>
  <config>
    <add key="repositoryPath" value="../Dependencies" />
  </config>
</configuration>

例如,如果您的解决方案(.sln 文件)位于 C:\Projects\MySolution 中,当您启用 NuGet 包还原时,将创建 .nuget 文件夹,如下所示:C:\Projects\MySolution.nuget 并将下载包到这样的目录:C:\Projects\MySolution\Dependencies

注意:由于某些(未知)原因,每次更新“repositoryPath”时,我都必须关闭并重新打开解决方案才能使更改生效


请注意,结束配置标记上缺少斜杠。
s
sgtz

对于那些使用 paket 作为他们的包管理器的人,你的依赖文件有一个自动符号链接选项:

storage: symlink

顺便说一句:paket 利用 nuget

参考:https://fsprojects.github.io/Paket/dependencies-file.html

如果您想尽可能少地修改,您可以使用脚本定期清理子目录。 IE。 Nuget 的默认行为是将文件从全局位置复制到本地包文件夹,因此之后删除这些文件。


T
Triynko

我只是使用 NTFS 连接将所有包文件夹直接放到存储库根目录上方的单个文件夹中。效果很好。跨多个解决方案的并行包还原没有问题。这样做的一个好处是您根本不必在源代码中重新配置任何内容,例如 .csproj 文件中的数百个相对提示路径。它通过让文件系统处理单个包文件夹的重定向和模拟来“正常工作”。

请注意“git”问题。尽管通过命令行的“git status”没有显示未暂存的更改,但我注意到 GitKraken 将“包”连接视为未暂存的文件。当您单击它时,它甚至会显示诸如“文件是目录”之类的错误。如果您变基、破坏连接并将其还原为包含原始文件路径文本的实际文件,GitKraken 还将尝试存储此“文件”。非常奇怪的行为。也许可以通过确保将包文件添加到您的 .gitignore 来解决它。


u
user3285954

以下是 NuGet 2.1 的说明:http://docs.nuget.org/docs/release-notes/nuget-2.1

无需编辑解决方案级别文件。

适用于 Visual Studio 2013 和三个解决方案共享项目。

不要忘记更新解决方案级别的 NuGet(.nuget 文件夹中的每个 nuget.exe)。