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

时间:2013-08-22 09:18:32

标签: nuget nuget-package solution

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

我已经看到有一些方法可以指出一个公共的包位置(可能在项目根级别,我们正在使用TFS源代码控制)和NuGet的2.1版本,请参阅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包。

14 个答案:

答案 0 :(得分:136)

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

  • 基本代码
    • 项目A
    • 项目B
    • 项目C
    • 解决方案
      • 解决方案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-&gt; New-&gt; File菜单,然后选择XML File模板。添加到NuGet.Config以下内容:

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

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

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

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

通过将NuGet.Config文件放在任何.sln文件上面的\ Solutions \中,我们正在利用NuGet将从&#34;当前工作目录向上递归导航文件夹结构的事实&#34;寻找要使用的NuGet.Config文件。 &#34;当前的工作目录&#34;这里有两个不同的东西,一个是NuGet.exe的执行路径,另一个是.sln文件的位置。

切换您的包文件夹

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

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

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

  1. 右键单击项目并选择“卸载项目”
  2. 右键单击项目,然后选择编辑your-xxx.csproj
  3. 查找对\ packages \的任何引用,并将它们更新到新位置。
    • 其中大部分将是&lt; HintPath&gt;引用,但不是全部。例如,WebGrease和Microsoft.Bcl.Build将具有需要更新的单独路径设置。
  4. 保存.csproj,然后右键单击该项目并选择Reload Project
  5. 一旦更新了所有.csproj文件,启动另一个Rebuild All,你就不会再有关于缺少引用的构建错误。此时您已完成,现在已将NuGet配置为使用共享Packages文件夹。

    截至NuGet 2.7.1(2.7.40906.75)和VStudio 2012

    首先要记住的是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并在&lt; configuration&gt;内添加以下内容:部分:

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

    构建解决方案

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

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

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

    nuget restore ..\YourSolution.sln
    

答案 1 :(得分:38)

不是为所有项目设置公共包位置,也可以在项目中更改HintPath,如下所示:

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

在大多数情况下,共享项目中只包含少量软件包,因此您可以轻松更改它。

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

答案 2 :(得分:21)

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

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

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

免责声明:我今天刚试过这个,我没有足够的长期经验来支持它!

答案 3 :(得分:18)

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

答案 4 :(得分:8)

已经没有必要修改nuget.targets了。它已在nuget 2.8(http://nuget.codeplex.com/workitem/2921)中修复。您只需要设置repositorypath。

答案 5 :(得分:3)

从Visual Studio 2013 Update 4和Nugget Package Manager版本&gt; 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文件级别的packages文件夹。

现在你可以使用命令'update-package -reinstall'找到每个.sln nuget控制台

如果你有同一级别的多个存储库以及在它们之间共享同一个包文件夹的内容,请尝试使用方法来获取一个文件夹。

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

但是这样你导致nuget包引用csproj指向一个文件夹,在你的repositorys路径之外。

答案 6 :(得分: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

答案 7 :(得分: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/

答案 8 :(得分:2)

将硬链接/打包到所需的共享位置。然后,对于没有特殊包位置的其他用户,您的项目不会被破坏。

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

mklink /prefix link_path Target_file/folder_path

答案 9 :(得分:2)

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

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

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

答案 10 :(得分:1)

VS 2013专业 NuGet 版本的简短摘要: 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”时,我都必须关闭并重新打开解决方案才能使更改生效

答案 11 :(得分:0)

对于使用paket作为其包管理器的用户,依赖项文件有一个自动符号链接选项:

storage: symlink

顺便说一句:程序包利用nuget

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

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

答案 12 :(得分:0)

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

只需当心“ git”问题。尽管通过命令行的“ git status”没有显示未暂存的更改,但我注意到GitKraken将“ package”结点视为未暂存的 file 。单击它甚至会显示诸如“文件是目录”之类的错误。如果您重新设置基准,销毁连接并将其还原为包含原始文件路径文本的实际文件,GitKraken还将尝试隐藏此“文件”。非常奇怪的行为。也许可以通过确保将软件包 file 添加到您的.gitignore中来解决该问题。

答案 13 :(得分:-1)

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

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

与Visual Studio 2013和三个共享项目的解决方案一起使用。

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