首页 文章

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

提问于
浏览
118

我一直在使用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包 .

13 回答

  • 2

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

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

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

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

  • 130

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

    • 代码库

    • 项目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-> New-> 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实际上相对于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 \文件夹 . 如果没有,请检查您的配置 .

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

    • 右键单击项目,然后选择“卸载项目”

    • 右键单击项目,然后选择编辑your-xxx.csproj

    • 查找对\ packages \的任何引用,并将它们更新到新位置 .

    • 其中大多数将是<HintPath>引用,但不是全部 . 例如,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并在<configuration>部分中添加以下内容:

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

    Note: 您可以使用绝对路径或相对路径 . 请记住,如果您使用$的相对路径,它相对于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>
    

    Note: 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
    
  • 20

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

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

    • 如果您从一个解决方案中获得了一个包,它会立即从您的包文件夹中删除旧版本(它可能会给我带来很大的麻烦,因为其他解决方案只会在需要时恢复 .

    • 如果您尝试从右键单击解决方案添加包,如果该包已经存在于另一个解决方案中,它将会看到它's there and show you the ' green tick ' instead of the ' install ' button. I usually install from right-click-on-project, so this doesn' t打扰我 .

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

  • 2

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

  • 3

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

  • 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文件级别的packages文件夹 .

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

    如果您有相同级别的多个存储库以及跨越它们共享相同包文件夹的内容,请尝试使用方式来获取一个文件夹 .

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

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

  • 1

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

  • -1

    用nuget 2.8.3更新我的经验 . 这很简单 . 所有这些都是右击解决方案的 enabled package restore . Edited 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

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

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

    mklink /prefix link_path Target_file/folder_path
    
  • 0

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

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

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

  • 2

    关于 VS 2013 professionalNuGet 的简短摘要:版本: 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

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

  • 18

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

    storage: symlink
    

    顺便说一句:paket利用nuget

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

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

  • 36

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

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

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

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

相关问题