Как обеспечить такую же версию пакета nuget для нескольких проектов С#?
У меня есть куча небольших проектов на С#, которые используют пару пакетов NuGet. Я хотел бы иметь возможность обновлять версию данного пакета автоматически. Более того: я хотел бы быть предупрежден, если проект использует другую версию из других.
Как я могу применить такую же зависимость версии для нескольких проектов С#?
Ответы
Ответ 1
Я считаю, что нашел установку, которая решает эту (и многие другие) проблему (и).
Я только что понял, что можно использовать папку в качестве источника nuget. Вот что я сделал:
root
+ localnuget
+ Newtonsoft.Json.6.0.1.nupkg
+ nuget.config
+ packages
+ Newtonsoft.Json.6.0.1
+ src
+ project1
nuget.config выглядит так:
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<add key="local source" value="localnuget">
</packageSources>
</configuration>
Вы можете добавить сервер Nuget в nuget.config, чтобы получить доступ к обновлениям или новым зависимостям во время разработки:
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
Как только вы закончите, вы можете скопировать .nupkg из кэша в папку localnuget
чтобы проверить это.
Есть 3 вещи, которые я люблю в этой настройке:
-
Теперь я могу использовать функции Nuget, такие как добавление реквизита и целей. Если у вас есть генератор кода (например, protobuf или Thrift), это становится бесценным.
-
Это (частично) решает проблему того, что Visual Studio не копирует все библиотеки DLL, потому что вам нужно указать зависимости в файле .nuspec
а .nuspec
автоматически загружает косвенные зависимости.
-
Раньше у меня был один файл решения для всех проектов, поэтому обновление пакетов nuget было проще. Я еще не пробовал, но думаю, что решил эту проблему тоже. У меня могут быть пакеты nuget для проекта, который я хочу экспортировать из данного решения.
Ответ 2
Спасибо, что спросили об этом, поэтому я не одинок. Я потратил немало времени на то, чтобы все проекты в моем решении использовали одну и ту же версию пакета. Пользовательский интерфейс NuGet (а также интерфейс командной строки) также способствует созданию разных версий среди проектов в рамках решения. В частности, когда к проекту добавляется новый проект, а в новый проект добавляется пакет X, NuGet слишком жадный, чтобы загрузить последнюю версию с nuget.org, вместо того, чтобы сначала использовать локальную версию, что было бы лучше по умолчанию.
Я полностью согласен с вами, что NuGet должен предупредить, если в решении используются разные версии пакета. И это должно помочь избежать этого и исправить такой лабиринт версии.
Лучшее, что я нашел сейчас, это перечислить все файлы packages.config в папке решения (ваши проекты-root), которые выглядят как
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
...
</packages>
затем сортировка xml-узлов по id и анализ номеров версий.
Если какой-либо пакет происходит с разными номерами версий, делая их одинаковыми, а затем запускает команду NuGet
Update-Package -ProjectName 'acme.lab.project' -Reinstall
должен исправить неправильные версии пакетов.
(Так как NuGet является открытым исходным кодом, конечно, было бы здорово заполучить наши руки и реализовать недостающую утилиту предотвращения конфликта версий.)
Ответ 3
Поскольку я не нашел другого способа обеспечить это, я написал модульное тестирование, которое не будет выполнено, если будут найдены разные версии пакетов в любом файле package.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";
/// <summary>
/// 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
/// </summary>
[Test]
public void EnforceCoherentReferences()
{
// Act
IDictionary<string, ICollection<PackageVersionItem>> packageVersionsById = new Dictionary<string, ICollection<PackageVersionItem>>();
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<XmlNode>())
{
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<PackageVersionItem> packageVersions))
{
packageVersions = new List<PackageVersionItem>();
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<KeyValuePair<string, ICollection<PackageVersionItem>>> 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<string> 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}";
}
}
}
Ответ 4
Я не знаю, как это сделать, но я нашел вкладку "Консолидация", чтобы помочь.
На этой вкладке отображается пакет, который отличается от версии. Оттуда вы можете выбрать проекты и использовать кнопку установки, чтобы установить для них ту же версию пакета.
![введите описание изображения здесь]()