it-roy-ru.com

Поддержка нескольких версий пакета NuGet в одном пакете библиотеки/NuGet

Что я хочу

Я хочу, чтобы моя библиотека работала с рядом версий пакета NuGet с прерыванием изменений в API между изменениями. Я не исследовал это далее, но этот путь выглядит многообещающим:

  • Ссылка на все версии библиотеки с различными API, указав псевдонимы пространства имен extern .
  • Создайте прокси для необходимых классов с флагами/исключениями/чем угодно, чтобы сказать, что на самом деле поддерживается.
  • Выберите правильный прокси во время выполнения в зависимости от того, какая версия фактически загружена в приложение.
  • Код, который зависит от несуществующего API, вызываться не будет, поэтому все должно работать нормально.

Хотя это может показаться сложным, оно имеет много преимуществ по сравнению с более простым подходом поддержки каждой версии в отдельной сборке:

  • Версия моей библиотеки не станет беспорядком, как 1.2.3-для-2.3.4-к-2.6.8. Я даже не знаю, как версионирование должно работать в этом случае.
  • Пользователям NuGet не придется выбирать между несколькими пакетами, один пакет подходит всем.
  • Обновление версий будет простым, не потребует удаления и добавления моего пакета.

Проблема

Однако неясно, возможно ли это вообще. Еще до того, как перейти к прокси и определить текущую версию, я застрял с основами.

Я даже не могу добавить несколько PackageReference узлов в мой .csproj, на самом деле работает только одна ссылка. Есть обходной путь для добавления внешних псевдонимов которые не поддерживаются NuGet напрямую, но я не могу добраться до этого момента, потому что не могу получить две ссылки. И если я получу два, я не смогу их различить.

Вопросы

  1. Можно ли реализовать поддержку нескольких версий, используя псевдонимы и прокси-серверы внешнего пространства имен?
  2. Если да, как добавить ссылки на несколько версий пакета NuGet и использовать их в коде?
  3. Если нет, то каков правильный подход?

Фон

Я работаю над библиотекой CsConsoleFormat для форматирования вывода консоли. Я хочу напрямую поддерживать все релевантные версии популярных пакетов командной строки, чтобы можно было добавить симпатичную справку командной строки и тому подобные вещи практически без программирования, независимо от того, какая библиотека синтаксического анализа используется для командной строки.

Я предполагаю, что заявление «я поддерживаю только последнюю версию» в моем случае несколько приемлемо, но я бы предпочел иметь более широкую поддержку, даже если это более сложно. В идеале я хочу пакет NuGet, который объявляет зависимость от самой низкой поддерживаемой версии, но поддерживает все до последней версии.

Прогресс на данный момент

Я вроде получил его на работу, но со многими проблемами. Смотрите выпуск на GitHub NuGet Home для более подробной информации.

8
Athari

Если вы настаиваете на внешних псевдонимах - вы можете добавить несколько ссылок на версии напрямую, как файл dll, а не как пакет nuget.

Предположим, что я хочу получить зависимость от пакета Newtonsoft.Json версии 10.0.3 + . Однако если у пользователя установлена ​​версия 11 - я хочу использовать универсальный класс JsonConverter<T>, доступный только в этой версии (11). Тогда мой csproj может выглядеть так:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <Version>1.0.4</Version>
  </PropertyGroup>
  <ItemGroup>
    <!-- Nuget reference -->
    <!-- Only this one will be included as dependency to the packed nuget -->
    <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
  </ItemGroup>
  <ItemGroup>
    <!-- Direct reference to the specific version -->
    <Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
      <!-- Path to v11 dll -->
      <HintPath>Newtonsoft.Json.v11.dll</HintPath>
      <Aliases>js11</Aliases>
      <SpecificVersion>true</SpecificVersion>
    </Reference>    
  </ItemGroup>
</Project>

Тогда у меня есть интерфейс прокси:

public interface ISerializer {
    string Serialize<T>(T obj);
}

И две реализации, v10 (использует глобальное пространство имен без псевдонимов):

using System;
using global::Newtonsoft.Json;

namespace NugetRefMain {
    internal class Js10Serializer : ISerializer
    {
        public string Serialize<T>(T obj)
        {
            Console.WriteLine(typeof(JsonConvert));
            return JsonConvert.SerializeObject(obj);
        }
    }
}

И v11

extern alias js11;
using System;
using js11::Newtonsoft.Json;

namespace NugetRefMain {
    internal class Js11Serializer : ISerializer {
        public string Serialize<T>(T obj) {
            // using JsonConverter<T>, only available in v11
            Console.WriteLine(typeof(JsonConverter<T>));
            return JsonConvert.SerializeObject(obj);
        }
    }
}

И, наконец, фабрика, которая создает сериализатор в зависимости от текущей доступной версии json.net:

public static class Serializers {
    public static ISerializer Create() {
        var version = typeof(JsonConvert).Assembly.GetName().Version;
        if (version.Major == 10)
            return new Js10Serializer();
        return new Js11Serializer();
    }
}

Теперь, если я упакую это как nuget - он будет зависеть от Newtonsoft.Json версии 10.0.3 и все. Однако, если пользователь установит Newtonsoft.Json версии 11 - он будет использовать возможности, доступные в этой версии.

Недостатки:

  • Visual Studio\Resharper intellisense иногда не нравится этот подход и выдает ошибки intellisense, когда в действительности все компилируется просто отлично.

  • У вас могут быть предупреждения о конфликте версий при компиляции.

4
Evk

NuGet разрешает только отдельные версии пакетов.

Если вы объявляете зависимость от минимально поддерживаемой версии, любой ссылочный проект может обновить зависимость до более новой версии.

Пока авторы зависимого пакета не вносят критических изменений, он должен найти.

Даже если вы используете отражение, чтобы посмотреть на используемые версии сборки, вы обнаружите, что многие авторы пакетов не меняют версию сборки между выпусками. Это сделано для того, чтобы избежать необходимости перенаправления привязки в классических проектах .NET Framework, поскольку все версии одинаковы, и NuGet выберет правильное DLL на основе версии разрешенного пакета потребляющего проекта. Опять же, это хорошо до тех пор, пока нет серьезных изменений.

Шаблон, который вы можете использовать для поддержки различных пакетов, заключается в предоставлении множества «платформенных» пакетов, из которых потребитель может выбирать. Пакет для конкретной платформы будет затем ссылаться на общий пакет с разделяемой логикой.

Тогда «платформой» будет, например, «MyLogic.XUnit» или «MyLogic.NUnit» (на примере помощников по тестированию) ссылаются на «MyLogic.Common»

3
Martin Ullrich

Это не полный ответ, но на вашей странице GitHub я заметил, что вы ссылаетесь на библиотеки .NET Standard и .NET Framework в своем проекте. Известно, что это НЕ работает правильно.

Цитировать объявление команды .NET Standard ,

.. Другим симптомом являются предупреждения во время сборки относительно версий сборки.

что может быть тем, с чем вы сталкиваетесь.

1
NGambit