当某些项目包含在多个解决方案中时,为所有解决方案设置一个通用的 nuget 包文件夹 [英] Setting up a common nuget packages folder for all solutions when some projects are included in multiple solutions

查看:94
本文介绍了当某些项目包含在多个解决方案中时,为所有解决方案设置一个通用的 nuget 包文件夹的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

<repositoryPath>..\..\[相对或绝对路径]</repositoryPath></设置>

NuGet 2.1 的发行说明(见上面的链接)建议采用这种格式:

<预><代码><配置><配置><add key="repositoryPath" value="..\..\[相对或绝对路径]"/></config></配置>

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

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

解决方案

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

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

使用 Visual Studio 2015 更新 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:

对于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 中打开您的解决方案并启动全部重建.忽略您将收到的所有构建错误,这是此时的预期.但是,这应该会在构建过程开始时启动 NuGet 包还原功能.验证您的 \Solutions\Packages\ 文件夹是否已在您想要的位置创建.如果没有,请检查您的配置.

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

  1. 右键单击项目并选择卸载项目
  2. 右键单击该项目并选择编辑 your-xxx.csproj
  3. 找到对 \packages\ 的任何引用并将它们更新到新位置.
    • 其中大部分将是 参考,但不是全部.例如,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 并在 中添加以下内容部分:

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

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

为 MSBuild 和 Visual Studio 设置公共包文件夹路径

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

<!-- Windows 特定命令--><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 更新为

$([System.IO.Path]::GetFullPath("$(SolutionDir)\..\Packages"))

注意: 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

I have been using NuGet to retrieve packages from external and internal package sources, which is very convenient. But I have realized that the packages are by default stored per solution, which is very frustrating when some projects with NuGet references are included in several solutions. Then the references are changed to other solutions package folder which may actually be unavailable to another developer or build machine.

I have seen that there are ways to point out a common package location (perhaps at the project root level, we are using TFS source control) with the release 2.1 of NuGet, see release notes . I am using NuGet v2.7

But I have tried to add nuget.config files without seeing any effect of this. Packages are still stored in the solution folder. Is there anything I have missed? There seems to be different structures of the xml node to add to the nuget.config file, depending on who is answering that question: Schwarzie suggests on another Stackoverflow thread:

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

The release notes for NuGet 2.1 (see link above) suggests this format:

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

I don't know which one of these, or any, or both will work in the end. I have tried both at solution level. Can the nuget.config file be placed on TFS project root level, or must it be in the solution directory? It seems that NuGet reads and applies the settings from these files in a certain order, why it would make sense to add them in several levels, where a nuget.config file on solution level would override one on the TFS project root level. Can this be clarified?

Do I need to remove all installed packages before those references will work? I would love if someone could provide a step-by-step instruction for moving from solution-specific nuget usage to a common package folder where projects that belong to several solutions can find their required nuget packages.

解决方案

I have a similar situation with external and internal package sources with projects referenced in more than one solution. I just got this working with one of our code bases today and it seems to be working with the developer workstations and our build server. The below process has this scenario in mind (although it shouldn't be hard to adapt to have the common packages folder else where).

  • Codebase
    • Project A
    • Project B
    • Project C
    • Solutions
      • Solution 1
      • Solution 2
      • Solution 3
      • Packages (this is the common one shared by all solutions)

Updated answer as of NuGet 3.5.0.1484 with Visual Studio 2015 Update 3

This process is a bit easier now than when I originally tackled this and thought it was time to update this. In general, the process is the same just with less steps. The result is a process that solves or provides the following:

  • Everything that needs to be commited to source code control is visible and tracked in the solution
  • Installing new packages or updating packages using the Package Manager in Visual Studio will use the correct repository path
  • After the initial configuration, no hacking of .csproj files
  • No modifications of developer workstation (Code is build ready on check out)

There are some potential downsides to be aware of (I haven't experience them yet, YMMV). See Benol's answer and comments below.

Add NuGet.Config

You will want to create a NuGet.Config file in the root of the \Solutions\ folder. Make sure this is a UTF-8 encoded file that you create, if you are not sure how to do this, use Visual Studio's File->New->File menu and then pick the XML File template. Add to NuGet.Config the following:

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

For the repositoryPath setting, you can specify an absolute path or relative path (recommended) using the $ token. The $ token is based on where the NuGet.Config is located (The $ token is actually relative to one level below the location of the NuGet.Config). So, if I have \Solutions\NuGet.Config and I want \Solutions\Packages I would need to specify $\..\Packages as the value.

Next, you will want to add a Solution Folder to you solution called something like "NuGet" (Right-Click on your solution, Add->New Solution Folder). Solution Folders are virtual folders that only exist in the Visual Studio solution and will not create an actual folder on the drive (and you can reference files from anywhere). Right-Click on your "NuGet" solution folder and then Add->Existing Item and select \Solutions\NuGet.Config.

The reason we are doing this is so that it is visible in the solution and should help with making sure it is properly committed to your source code control. You may want to do this step for each solution in your codebase that is participating with your shared projects.

By placing the NuGet.Config file in \Solutions\ above any .sln files, we are taking advantage of the fact that NuGet will recursively navigate the folder structure upwards from the "current working directory" looking for a NuGet.Config file to use. The "current working directory" means a couple of different things here, one is the execution path of NuGet.exe and the other is the location of the .sln file.

Switching over your packages folder

First, I highly recommend you go through each of your solution folders and delete any \Packages\ folders that exist (you'll need to close Visual Studio first). This makes it easier to see where NuGet is placing your newly configured \Packages\ folder and ensures that any links to wrong \Packages\ folder will fail and can then be fixed.

Open your solution in Visual Studio and kick off a Rebuild All. Ignore all of the build errors you will receive, this is expected at this point. This should kick off the NuGet package restore feature at the start of the build process however. Verify that your \Solutions\Packages\ folder has been created in the spot you want. If it hasn't, review your configuration.

Now, for each project in your solution you will want to:

  1. Right-click on the project and select Unload Project
  2. Right-click on the project and select Edit your-xxx.csproj
  3. Find any references to \packages\ and update them to the new location.
    • Most of these will be <HintPath> references, but not all of them. For example, WebGrease and Microsoft.Bcl.Build will have separate path settings that will need to be updated.
  4. Save the .csproj and then Right-click on the project and select Reload Project

Once all of your .csproj files have been updated, kick off another Rebuild All and you should have no more build errors about missing references. At this point you are done, and now have NuGet configured to use a shared Packages folder.

As of NuGet 2.7.1 (2.7.40906.75) with VStudio 2012

First off the thing to keep in mind is that nuget.config does not control all of the path settings in the nuget package system. This was particularly confusing to figure out. Specifically, the issue is that msbuild and Visual Studio (calling msbuild) do not use the path in nuget.config but rather are overriding it in the nuget.targets file.

Environment Preparation

First, I would go through your solution's folder and remove all \packages\ folders that exist. This will help ensure that all packages are visibly installing into the correct folder and to help discover any bad path references throughout your solutions. Next, I would make sure you have the latest nuget Visual Studio extension installed. I would also make sure you have the latest nuget.exe installed into each solution. Open a command prompt and go into each $(SolutionDir)\ .nuget\ folder and execute the following command:

nuget update -self

Setting common package folder path for NuGet

Open each $(SolutionDir)\ .nuget\NuGet.Config and add the following inside the <configuration> section:

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

Note: You can use an absolute path or a relative path. Keep in mind, if you are using a relative path with $ that it is relative to one level below the location of the NuGet.Config (believe this is a bug).

Setting common package folder path for MSBuild and Visual Studio

Open each $(SolutionDir)\ .nuget\NuGet.targets and modify the following section (note that for non-Windows there is another section below it):

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

Update PackagesDir to be

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

Note: The GetFullPath will resolve our relative path into an absolute path.

Restoring all of the nuget packages into common folder

Open a command prompt and goto each $(SolutionDir)\ .nuget and execute the following command:

nuget restore ..\YourSolution.sln

At this point, you should have a single \packages\ folder in your common location and none within any of your solution folders. If not, then verify your paths.

Fixing project references

Open every .csproj file in a text editor and find any references to \packages and update them to the correct path. Most of these will be <HintPath> references, but not all of them. For example, WebGrease and Microsoft.Bcl.Build will have separate path settings that will need to be updated.

Build your solution

Open your solution in Visual Studio and kick off a build. If it complains about missing packages that need to be restored, don't assume that the package is missing and needs to be restored (error can be misleading). It could be a bad path in one of your .csproj files. Check that first before restoring the package.

Have a build error about missing packages?

If you have already verified that the paths in your .csproj files are correct, then you have two options to try. If this is the result of updating your code from source code control then you can try checking out a clean copy and then building that. This worked for one of our developers and I think there was an artifact in the .suo file or something similar. The other option is to manually force a package restore using the command line in the .nuget folder of the solution in question:

nuget restore ..\YourSolution.sln

这篇关于当某些项目包含在多个解决方案中时,为所有解决方案设置一个通用的 nuget 包文件夹的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆