如何跨多个c#项目强制执行相同的nuget包版本?

我有一些使用几个NuGet包的小型C#项目。 我希望能够自动更新给定包的版本。 更重要的是:如果项目使用与其他项目不同的版本,我希望收到警告。

如何在多个C#项目中强制实施相同的版本依赖?

谢谢你问这个 – 所以我并不孤单。 我花了大量时间确保我的解决方案中的所有项目都使用相同的软件包版本。 NuGet用户界面(以及命令行界面)也有助于在解决方案中的项目中具有不同的版本。 特别是当一个新项目被添加到解决方案中并且包X将被添加到新项目中时,NuGet非常贪婪地从nuget.org下载最新版本而不是首先使用本地版本,这将是更好的默认处理。

我完全同意你的观点,如果在解决方案中使用不同版本的软件包,NuGet应该发出警告。 它应该有助于避免这种情况并修复这样的版本迷宫。

我现在发现的最好的方法是枚举解决方案文件夹(你的项目 – 根)中的所有packages.config文件,它们看起来像

    ...  

然后按id排序xml节点并分析版本号。

如果任何包具有不同的版本号,则使它们全部相等,然后运行NuGet命令

 Update-Package -ProjectName 'acme.lab.project' -Reinstall 

应修复错误的包版本。

(由于NuGet是开源的,所以让我们的手弄脏并实现丢失版本冲突避免实用程序肯定是一件很酷的事情。)

我相信我找到了一个解决这个(和许多其他)问题的设置。

我刚刚意识到可以使用文件夹作为nuget源。 这是我做的:

 root + localnuget + Newtonsoft.Json.6.0.1.nupkg + nuget.config + packages + Newtonsoft.Json.6.0.1 + src + project1 

nuget.config看起来像这样:

         

您可以将Nuget服务器添加到nuget.config,以便在开发期间访问更新或新的依赖项:

  

完成后,您可以将.nupkg从cache [1]复制到localnuget文件夹以进行检查。

我喜欢这个设置有3件事:

  1. 我现在能够使用Nugetfunction,例如添加道具和目标。 如果你有一个代码生成器(例如protobuf或thrift),这就变得无价了。

  2. 它(部分)解决了Visual Studio不复制所有DLL的问题[2],因为你需要在.nuspec文件中指定依赖.nuspec ,nuget会自动加载间接依赖项。

  3. 我曾经为所有项目提供单个解决方案文件,因此更新nuget包更容易。 我还没试过,但我想我也解决了这个问题。 我可以为我想从给定解决方案导出的项目提供nuget包。

[1] http://www.hanselman.com/blog/HowToAccessNuGetWhenNuGetorgIsDownOrYoureOnAPlane.aspx

[2] http://www.google.com/search?q=visual+studio+not+copying+referenced+dll

我不知道如何强制执行,但我找到了“合并”标签来帮助。 此选项卡显示整个解决方案中包含不同版本的包。 从那里,您可以选择项目并使用安装按钮为它们安装相同的软件包版本。

在此处输入图像描述

由于我还没有找到另一种方法来强制执行此操作,因此我编写了一个unit testing,如果在任何子文件夹中的任何packages.config中找到不同的软件包版本,它将失败。 由于这可能对其他人有用,您可以在下面找到代码。 您必须调整GetBackendDirectoryPath()中完成的根文件夹的分辨率。

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Xml; using NUnit.Framework; namespace Base.Test.Unit { [TestFixture] public class NugetTest { private const string PACKAGES_CONFIG_FILE_NAME = "packages.config"; private const string BACKEND_DIRECTORY_NAME = "DeviceCloud/"; private const string PACKAGES_NODE_NAME = "packages"; private const string PACKAGE_ID_ATTRIBUTE_NAME = "id"; private const string PACKAGE_VERSION_ATTRIBUTE_NAME = "version"; ///  /// Tests that all referenced nuget packages have the same version by doing: /// - Get all packages.config files contained in the backend /// - Retrieve the id and version of all packages /// - Fail this test if any referenced package has referenced to more than one version accross projects /// - Output a message mentioning the different versions for each package ///  [Test] public void EnforceCoherentReferences() { // Act IDictionary> packageVersionsById = new Dictionary>(); foreach (string packagesConfigFilePath in GetAllPackagesConfigFilePaths()) { var doc = new XmlDocument(); doc.Load(packagesConfigFilePath); XmlNode packagesNode = doc.SelectSingleNode(PACKAGES_NODE_NAME); if (packagesNode != null && packagesNode.HasChildNodes) { foreach (var packageNode in packagesNode.ChildNodes.Cast()) { if (packageNode.Attributes == null) { continue; } string packageId = packageNode.Attributes[PACKAGE_ID_ATTRIBUTE_NAME].Value; string packageVersion = packageNode.Attributes[PACKAGE_VERSION_ATTRIBUTE_NAME].Value; if (!packageVersionsById.TryGetValue(packageId, out ICollection packageVersions)) { packageVersions = new List(); packageVersionsById.Add(packageId, packageVersions); } //if (!packageVersions.Contains(packageVersion)) if(!packageVersions.Any(o=>o.Version.Equals(packageVersion))) { packageVersions.Add(new PackageVersionItem() { SourceFile = packagesConfigFilePath, Version = packageVersion }); } if (packageVersions.Count > 1) { //breakpoint to examine package source } } } } List>> packagesWithIncoherentVersions = packageVersionsById.Where(kv => kv.Value.Count > 1).ToList(); // Assert string errorMessage = string.Empty; if (packagesWithIncoherentVersions.Any()) { errorMessage = $"Some referenced packages have incoherent versions. Please fix them by adapting the nuget reference:{Environment.NewLine}"; foreach (var packagesWithIncoherentVersion in packagesWithIncoherentVersions) { string packageName = packagesWithIncoherentVersion.Key; string packageVersions = string.Join("\n ", packagesWithIncoherentVersion.Value); errorMessage += $"{packageName}:\n {packageVersions}\n\n"; } } Assert.IsTrue(packagesWithIncoherentVersions.Count == 0,errorMessage); //Assert.IsEmpty(packagesWithIncoherentVersions, errorMessage); } private static IEnumerable GetAllPackagesConfigFilePaths() { return Directory.GetFiles(GetBackendDirectoryPath(), PACKAGES_CONFIG_FILE_NAME, SearchOption.AllDirectories) .Where(o=>!o.Contains(".nuget")); } private static string GetBackendDirectoryPath() { string codeBase = Assembly.GetExecutingAssembly().CodeBase; var uri = new UriBuilder(codeBase); string path = Uri.UnescapeDataString(uri.Path); return Path.GetDirectoryName(path.Substring(0, path.IndexOf(BACKEND_DIRECTORY_NAME, StringComparison.Ordinal) + BACKEND_DIRECTORY_NAME.Length)); } } public class PackageVersionItem { public string SourceFile { get; set; } public string Version { get; set; } public override string ToString() { return $"{Version} in {SourceFile}"; } } }