149

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

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

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

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

4

14 回答 14

153

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

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

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

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

  • 需要提交到源代码控制的所有内容在解决方案中都是可见和跟踪的
  • 使用 Visual Studio 中的包管理器安装新包或更新包将使用正确的存储库路径
  • 初始配置后,不会对 .csproj 文件进行黑客攻击
  • 无需修改开发人员工作站(代码已在签出时构建)

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

添加 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\ 文件夹是否已在您想要的位置创建。如果没有,请检查您的配置。

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

  1. 右键单击项目并选择卸载项目
  2. 右键单击项目并选择 Edit your-xxx.csproj
  3. 找到对 \packages\ 的任何引用并将它们更新到新位置。
    • 其中大部分将是 <HintPath> 引用,但不是全部。例如,WebGrease 和 Microsoft.Bcl.Build 将具有需要更新的单独路径设置。
  4. 保存 .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 并在 <configuration> 部分中添加以下内容:

<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 的任何引用并将它们更新到正确的路径。其中大部分将是 <HintPath> 引用,但不是全部。例如,WebGrease 和 Microsoft.Bcl.Build 将具有需要更新的单独路径设置。

构建您的解决方案

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

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

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

nuget restore ..\YourSolution.sln
于 2013-10-08T22:52:56.190 回答
39

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

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

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

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

于 2014-09-18T11:15:15.560 回答
22

我尝试使用最新版本的 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>

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

  • 如果您从一个解决方案“更新”一个包,它会立即从您的包文件夹中删除旧版本(它不知道您是否有另一个解决方案指向那里)。这并没有让我很困扰,因为其他解决方案只会在需要时恢复。
  • 如果您尝试从右键单击解决方案添加包,如果该包已经存在于另一个解决方案中,它将看到它在那里并显示“绿色勾号”而不是“安装”按钮。我通常从右键单击项目安装,所以这根本不会打扰我。

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

于 2013-12-18T14:32:57.663 回答
21

我有 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 将自动在您指定的新集中目录中恢复丢失的包。

于 2015-12-02T08:33:21.020 回答
8

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

于 2014-01-28T07:05:37.727 回答
3

我编写了一个 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

于 2016-09-29T11:34:45.660 回答
3

从 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 将一个文件夹指向存储库路径之外的一个文件夹。

于 2015-10-02T18:08:17.940 回答
2

更新我对 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/

于 2014-11-09T05:56:35.123 回答
2

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

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

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

于 2016-08-08T21:11:07.267 回答
2

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

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

mklink /prefix link_path Target_file/folder_path
于 2016-01-23T19:36:36.967 回答
1

使用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”时,我都必须关闭并重新打开解决方案才能使更改生效

于 2015-05-13T01:00:19.910 回答
1

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

storage: symlink

顺便说一句:paket 利用 nuget

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

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

于 2018-07-12T22:53:58.393 回答
0

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

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

于 2019-12-30T18:14:16.413 回答
-1

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

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

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

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

于 2014-06-06T14:09:47.983 回答