简体   繁体   English

保证相同版本的nuget包

[英]Guarantee same version of nuget packages

We have a framework that is split up into lots of separate projects in one solution. 我们有一个框架,在一个解决方案中分成许多单独的项目。 I now want to create NuGet packages for each separate project, but guarantee that only one version of the framework can be used in one solution (possibly across several projects). 我现在想为每个单独的项目创建NuGet包, 保证只能在一个解决方案中使用一个版本的框架(可能跨多个项目)。

For example, say the framework is made up of two projects: 例如,假设框架由两个项目组成:

Framework
   Framework_1
   Framework_2

Now when using this framework one project might reference Framework_1 , while another project references Framework_2 . 现在,当使用此框架时,一个项目可能引用Framework_1 ,而另一个项目引用Framework_2 I want to make sure that both packages have the same version (bonus points if there's an easy single-step process to upgrade to a newer version) 我想确保两个软件包具有相同的版本(如果有一个简单的单步过程升级到新版本,则可获得奖励积分)

I thought I would just define one solution level Framework package that all other packages depend on strictly. 我想我会定义一个解决方案级别的Framework包,所有其他包都严格依赖它。 The problem is that NuGet has no problems simply installing several versions of the solution level package. 问题是NuGet只需安装多个版本的解决方案级别包就没有问题。

Basically I tried the following: 基本上我尝试了以下内容:

Solution-level nuspec file: 解决方案级别的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>

And one nuspec package for one part: 一个部分的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>

The problem now is if I tried to install, say another My.Framework.EF package with version 1.0.1 and an explicit dependency on My.Framework 1.0.1 Visual Studio would just install My.Framework twice - once with version 1.0.0 and once with 1.0.1. 现在的问题是,如果我尝试安装,说另一个版本1.0.1 My.Framework.EF包和My.Framework 1.0.1的显式依赖, Visual Studio只会安装My.Framework两次 - 一次使用版本1.0.0和一次1.0.1。

you can constrain the version of your package by using the following syntax in your packages.config like : 您可以通过在packages.config中使用以下语法来约束包的版本,如:

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

Also from original nuget documentation : When you create a NuGet package, you can specify dependencies for the package in the .nuspec file. 同样来自原始nuget文档:创建NuGet包时,可以在.nuspec文件中指定包的依赖关系。

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

In the example, version 1 and version 2.9 would be acceptable, but not 0.9 or 3.0. 在示例中,版本1和版本2.9是可接受的,但不是0.9或3.0。

I asume you can limit it this way to a single or certain range of versions. 我认为您可以通过这种方式将其限制为单个或特定范围的版本。 Here you can read more about it. 在这里,您可以阅读更多相关信息。

You can create a simple unit test inside your solution to warn you when you have a problem. 您可以在解决方案中创建一个简单的单元测试,以便在出现问题时向您发出警告。 The code is below. 代码如下。

You will need to install-package NuGet.Core inside your unit-test project for the below code to work. 您需要在单元测试项目中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;
    }
}

I would rip out the "Solution level NuGet Package", and divide your framework up into components, and create a NuGet package per component. 我会删除“解决方案级NuGet包”,并将您的框架划分为组件,并为每个组件创建一个NuGet包。 No one is going to have 1 single project that references you're "Framework Wrapper" NuGet package, and code for Business Logic, Data Access, and WCF inside that single project. 没有人会有一个单独的项目引用你的“Framework Wrapper”NuGet包,以及单个项目中的业务逻辑,数据访问和WCF的代码。

Then what you need to do is, iron out what your dependency logic truly is, and what is the reasoning behind wanting to strictly enforce a same-version policy . 那么你需要做的是,弄清楚你的依赖逻辑究竟是什么,以及想要严格执行同一版本策略背后的原因是什么。

For example, let's say My.Framework.BL has a dependency on My.Framework.DAL. 例如,假设My.Framework.BL依赖于My.Framework.DAL。 So at this point you only have 2 Nuspec files, and 2 NuGet packages, with the .nuspec of your My.Framework.BL looking like this: 所以此时你只有2个Nuspec文件和2个NuGet包,你的My.Framework.BL的.nuspec看起来像这样:

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

And with your My.Framework.DAL containing no My.Framework specific dependencies. 并且您的My.Framework.DAL不包含My.Framework特定的依赖项。

This is fine, and your solution of wanting to tightly couple the number that is associated with the version is problematic for a few reasons. 这很好,并且由于某些原因,您希望紧密耦合与版本相关联的数字的解决方案存在问题。 The first and most important is it that it will confuse your framework consumers if you updated My.Framework.DAL when it has 0 changes, but you had to update it because you changed My.Framework.BL. 第一个也是最重要的是,如果你在更改了0时更新了My.Framework.DAL,它会让你的框架消费者感到困惑,但你必须更新它,因为你改变了My.Framework.BL。

You could go a month, or more possibly, and not have to update a My.Framework dependency, depending on the level of abstraction of your framework, and to what degree of low-level programming you're doing. 您可能需要一个月或更长时间,而不必更新My.Framework依赖项,具体取决于框架的抽象级别,以及您正在执行的低级编程程度。 In my opinion, having to update Core Framework dll versions when there aren't actually any new changes is a MUCH bigger problem than the version numbers of all My.Framework dlls being the same. 在我看来,当没有实际任何新的更改时,必须更新Core Framework DLL版本是一个比所有My.Framework dll版本号相同的问题。 Cheers. 干杯。 :) :)

Here are the nuspec references docs. 以下是nuspec参考文档。

It turns out that you can call Install-Package $package.Id -version <someVersion> inside Install.ps1 which will then cause the originally installed version to be uninstalled and the specified version to be installed. 事实证明,您可以 Install.ps1中调用Install-Package $package.Id -version <someVersion> 这将导致卸载最初安装的版本并安装指定的版本。

A slightly simplified version is the following: 稍微简化的版本如下:

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM