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

Mat*_*son 130 solution nuget nuget-package

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

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

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

<settings>
  <repositoryPath>..\..\[relative or absolute path]</repositoryPath>
</settings>
Run Code Online (Sandbox Code Playgroud)

NuGet 2.1的发行说明(见上面的链接)表明了这种格式:

<configuration>
  <config>
    <add key="repositoryPath" value="..\..\[relative or absolute path]" />
  </config>
</configuration>
Run Code Online (Sandbox Code Playgroud)

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

在这些引用工作之前,是否需要删除所有已安装的软件包?我很乐意,如果有人可以提供逐步说明,从特定于解决方案的nuget使用转移到一个公共包文件夹,其中属于多个解决方案的项目可以找到他们所需的nuget包.

Ver*_*mis 140

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

  • 代码库
    • 项目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>
Run Code Online (Sandbox Code Playgroud)

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

接下来,您需要为解决方案添加一个名为"NuGet"的解决方案(右键单击您的解决方案,添加 - >新建解决方案文件夹).解决方案文件夹是仅存在于Visual Studio解决方案中的虚拟文件夹,不会在驱动器上创建实际文件夹(您可以从任何位置引用文件).右键单击"NuGet"解决方案文件夹,然后单击Add-> Existing Item并选择\ 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,然后右键单击该项目并选择Reload Project

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

截至VG 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
Run Code Online (Sandbox Code Playgroud)

为NuGet设置公共包文件夹路径

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

<config>
    <add key="repositorypath" value="$\..\..\..\Packages" />
</config>
Run Code Online (Sandbox Code Playgroud)

注意:您可以使用绝对路径或相对路径.请记住,如果您使用$的相对路径,它相对于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>
Run Code Online (Sandbox Code Playgroud)

更新PackagesDir为

<PackagesDir>$([System.IO.Path]::GetFullPath("$(SolutionDir)\..\Packages"))</PackagesDir>
Run Code Online (Sandbox Code Playgroud)

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

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

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

nuget restore ..\YourSolution.sln
Run Code Online (Sandbox Code Playgroud)

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

修复项目参考

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

构建您的解决方案

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

有关丢失包的构建错误?

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

nuget restore ..\YourSolution.sln
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个答案表明了nuget的刚性.必须创建这样一个复杂,刚性的结构才能实现这样一个简单的概念: - "在解决方案之间共享相同的组件"表明整个设计的设计很差. (6认同)

小智 38

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

<HintPath>$(SolutionDir)\packages\EntityFramework.6.1.0\lib\net40\EntityFramework.dll</HintPath>
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这将很有效,直到您更新包,并用新的相对路径覆盖HintPath.在包含大量软件包的大型解决方案中变得相当繁琐.上帝禁止你必须运行Update-Package -Reinstall ... (15认同)
  • 亚当是对的.对于一个令人难以置信的愚蠢问题,这是最简单的解决方案. (2认同)
  • AFAIK $(SolutionDir)仅在通过VS完成构建时设置.所以没有直接通过msbuild.exe构建,除非你设置/ p:SolutionDir = path (2认同)

Ben*_*jol 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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 这是推荐的**推荐方式.在接受的答案中进行nuget恢复的旧的msbuild集成方法是pita,我可以确认将NuGet.config与sln工作一起用于自动包恢复.把它放在一个共同的父目录中我无法确认. (4认同)
  • 适用于Visual Studio 2015和Nuget 3.4.3 (2认同)

Mat*_*ieu 19

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

%APPDATA%\Roaming\NuGet\NuGet.Config
Run Code Online (Sandbox Code Playgroud)

这是我的文件的内容:

<?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>
Run Code Online (Sandbox Code Playgroud)

所以所有包都转到"C:\ Projects \nugetpackages"文件夹,无论解决方案在哪里.

在所有解决方案中,只需删除现有的"包"文件夹即可.然后构建您的解决方案,NuGet将自动恢复您指定的新的集中式目录中缺少的包.

  • 这是今天最简单的解决方案,但你的答案中缺少一件事.你仍然需要在每个项目的csproj文件中处理HintPath.他们不会自动瞄准新的道路.我对么? (2认同)

小智 8

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