【问题标题】:Guarantee same version of nuget packages保证相同版本的nuget包
【发布时间】:2015-09-01 06:38:14
【问题描述】:

我们有一个框架,该框架在一个解决方案中分为许多单独的项目。我现在想为每个单独的项目创建 NuGet 包,但是保证只能在一个解决方案中使用框架的一个版本(可能跨多个项目)。

例如,假设框架由两个项目组成:

Framework
   Framework_1
   Framework_2

现在,当使用这个框架时,一个项目可能引用Framework_1,而另一个项目引用Framework_2。我想确保两个软件包具有相同的版本(如果有一个简单的单步过程可以升级到新版本,则可以加分)

我想我只定义一个解决方案级别的框架包,所有其他包都严格依赖它。问题是 NuGet 只需安装几个版本的解决方案级别包就没有问题。

基本上我尝试了以下方法:

解决方案级nuspec文件:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>My.Framework</id>
    <version>1.0.0</version>
    <title>My.Framework</title>
    <authors>voo</authors>
    <owners>voo</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Some Framework Solution Package</description>
    <copyright>Copyright ©  2015</copyright>
  </metadata>
</package>

还有一个 nuspec 包用于某一部分:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>My.Framework.BL</id>
    <version>1.0.0</version>
    <title>My.Framework.BL</title>
    <authors>voo</authors>
    <owners>voo</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Business Layer</description>
    <copyright>Copyright ©  2015</copyright>
    <dependencies> 
        <dependency id="My.Framework" version="[1.0.0]"/>
    </dependencies>
  </metadata>
</package>

现在的问题是,如果我尝试安装另一个 My.Framework.EF 软件包,其版本为 1.0.1 并且显式依赖于 My.Framework 1.0.1 Visual Studio 只会安装 My.Framework 两次 - 一次是版本 1.0 .0 和 1.0.1 一次。

【问题讨论】:

  • 为什么不明确说明您要安装的版本?还是我错过了什么?
  • 我是否正确地说你想要的是某种包包,所有子包都使用相同的版本?我必须承认我发现你的问题有点模糊。
  • @Pseudonym 因为这允许某人意外更新框架的一部分,但不能更新其他部分。这个想法是有一个位置来指定版本,或者至少有某种保证可以捕获此类错误。
  • 您使用的是构建服务器吗?如果有,是哪一个?
  • @Iain Team Foundation Build Server,但我确实希望它在本地编译时与普通 Visual Studio 2013 一样工作。

标签: c# visual-studio-2013 nuget nuget-package nuget-spec


【解决方案1】:

您可以通过在您的 packages.config 中使用以下语法来限制您的包的版本,例如:

<package id="jQuery" version="1.9.1" allowedVersions="[1.9.1]" />

也来自原始 nuget 文档: 创建 NuGet 包时,可以在 .nuspec 文件中指定包的依赖项。

<dependency id="ExamplePackage" version="[1,3)" />

在示例中,可以接受版本 1 和 2.9,但不能接受 0.9 或 3.0。

我认为您可以通过这种方式将其限制为单个或特定范围的版本。 Here你可以阅读更多。

【讨论】:

  • 考虑到它描述了原始帖子中已经显示的语法并且根本没有解决所描述的问题,我无法理解为什么它会获得 6 个赞成票。我仍然在解决方案文件夹中有一个 package.config,它有 &lt;package id="My.Framework" version="1.0.0" allowedVersions="[1.0.0]" /&gt;&lt;package id="My.Framework" version="1.0.1" /&gt;,因此能够安装我想要的任何版本。
  • &lt;package id="My.Framework" version="1.0.0" allowedVersions="[1.0.0]" /&gt;&lt;package id="My.Framework" version="1.0.1" /&gt; 真的对你有意义吗?
  • 不,它没有(在我看来确实像一个错误),但如果你真的尝试它就会发生这种情况。
【解决方案2】:

您可以在解决方案中创建一个简单的单元测试,以便在遇到问题时向您发出警告。代码如下。

您需要在您的单元测试项目中 install-package NuGet.Core 才能使以下代码正常工作。

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NuGet;

[TestClass]
public class NugetPackagesTest
{
    /// <summary>
    /// This test method makes sure that we do not install different versions of the same nuget package
    /// across the solution. For example this test will fail if one project references EntityFramework
    /// version 6.1.3 and another project references version 6.2.0. Having different versions of the same
    /// package installed often results in unexpected and hard-to-understand errors.
    /// </summary>
    [TestMethod]
    public void PackagesAccrossProjectsAreOfSameVersion()
    {
        var dir = GetSolutionRoot();

        Debug.Assert(dir != null, nameof(dir) + " != null");

        var filePaths = Directory.GetFiles(dir.FullName, "*packages.config", SearchOption.AllDirectories);
        var installedPackages = filePaths
            .Select(t => new PackageReferenceFile(t))
            .SelectMany(t => t.GetPackageReferences().Select(x => new { File = t, Package = x }))
            .GroupBy(t => t.Package.Id)
            .ToList();

        foreach (var package in installedPackages)
        {
            var versions = package
                .Select(t => t.Package.Version.ToNormalizedString())
                .Distinct()
                .ToList();

            var report = package
                .Select(t => $"{t.Package.Version} @ {t.File.FullPath}")
                .OrderBy(t => t);

            Assert.IsTrue(
                versions.Count == 1,
                $"Multiple versions of package {package.Key} are installed: {string.Join(", ", versions)}.\n" +
                $"{string.Join("\n", report)}");
        }
    }

    private static DirectoryInfo GetSolutionRoot()
    {
        var current = AppDomain.CurrentDomain.BaseDirectory;
        var dir = Directory.GetParent(current);

        while (dir != null)
        {
            // TODO: replace with name your solution's folder.
            if (dir.Name == "MySolution")
            {
                dir = dir.Parent;
                break;
            }

            dir = dir.Parent;
        }

        return dir;
    }
}

【讨论】:

    【解决方案3】:

    我会删除“解决方案级别的 NuGet 包”,并将您的框架划分为组件,并为每个组件创建一个 NuGet 包。没有人会拥有 1 个引用您的“框架包装器”NuGet 包的单个项目,以及该单个项目中的业务逻辑、数据访问和 WCF 代码。

    那么你需要做的是,弄清楚你的依赖逻辑到底是什么,以及想要严格执行同版本策略背后的原因是什么。

    例如,假设 My.Framework.BL 依赖于 My.Framework.DAL。因此,此时您只有 2 个 Nuspec 文件和 2 个 NuGet 包,您的 My.Framework.BL 的 .nuspec 如下所示:

    <dependencies>
      <dependency id="My.Framework.DAL" version="1.0.0" />
    </dependencies>
    

    并且您的 My.Framework.DAL 不包含 My.Framework 特定依赖项。

    这很好,您希望将与版本关联的数字紧密耦合的解决方案存在问题,原因有几个。第一个也是最重要的一点是,如果您在 My.Framework.DAL 有 0 次更改时更新它会混淆您的框架使用者,但您必须更新它,因为您更改了 My.Framework.BL。

    您可能需要一个月或更长时间,而不必更新 My.Framework 依赖项,这取决于您的框架的抽象级别以及您正在执行的低级编程程度。在我看来,在实际上没有任何新更改的情况下必须更新 Core Framework dll 版本是一个比所有 My.Framework dll 的版本号相同的问题要大得多。干杯。 :)

    Here 是 nuspec 参考文档。

    【讨论】:

    • 虽然对于外部框架来说当然是一个合理的想法,但考虑到额外的支持和测试成本以及非常有限的收益,公司内部框架这样做没有任何好处。
    【解决方案4】:

    原来你可以调用Install-Package $package.Id -version &lt;someVersion&gt;insideInstall.ps1,然后会导致原来安装的版本卸载,安装指定的版本。

    稍微简化的版本如下:

    param($installPath, $toolsPath, $package, $project)
    
    function GetInstallingVersion() {
        $package.Version
    }
    
    # Gets the current version of the used framework. 
    # If no framework is yet installed, we set the framework version 
    # to the one that's being installed right now.
    function GetCurrentFrameworkVersion() {
        $solutionPath = Split-Path $dte.Solution.FileName
        $fwkVersionFile = "${solutionPath}\framework_version.txt"
        if (Test-Path $fwkVersionFile) {
            return Get-Content $fwkVersionFile
        } 
        else {
            $installingVersion = GetInstallingVersion
            $installingVersion > $fwkVersionFile
            return $installingVersion
        }
    }
    
    $currentFwkVersion = GetCurrentFrameworkVersion
    $installingVersion = GetInstallingVersion
    
    if ($currentFwkVersion -ne $installingVersion) {
        Install-Package $package.Id -version $currentFwkVersion
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-21
      • 1970-01-01
      • 2021-03-14
      • 2021-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多