Независимые от версии ссылочные зависимости в управляемых библиотеках классов

2

Я работаю над приложением для log4net, и я столкнулся с проблемой управления зависимостями от версии log4net, созданной моей библиотекой классов против фактической версии, развернутой на сайте. Моя библиотека классов должна ссылаться на dll log4net, и поэтому она привязана к версии, на которую я ссылаюсь во встроенное время. Тем не менее, сайты, на которых будет развернут этот компонент, будут иметь разные версии log4net, некоторые из которых старше меня, некоторые из них будут более новыми. Как мне подойти к этой проблеме? Я не хочу выпускать новую версию своего приложения для каждой новой версии log4net и возлагаю ответственность за их корректное сопоставление с моими пользователями. Я также не хочу просить моих пользователей-подписчиков выполнять сложные бок о бок манифеста. Я просто хочу, чтобы мой appender был просто скопирован в конечное местоположение пользователя и работал в готовом виде с любой версией log4net.

Достижимо ли это? Мне что-то не хватает?

Обновление

Единственное рабочее решение - использовать манифест. Я тестировал с двумя сборками log4net на домашней основе, и добавление следующего раздела конфигурации решает мою проблему:

<runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity name="log4net"
                              publicKeyToken="..."
                              culture="neutral" />
            <bindingRedirect oldVersion="1.2.10.0"
                             newVersion="..."/>
         </dependentAssembly>
      </assemblyBinding>
   </runtime>

где publicKeyToken является фактическим ключевым токеном реальной сборки log4net, 1.2.10 - это версия, с которой мой appender построен, а newVersion - в настоящее время развернутая версия на сайте. Раздел можно добавить к развернутому appconfig или webconfig (это можно сделать и в конфигурации машины, но я не рекомендую это...).

Теги:
reflection
reference
log4net

9 ответов

2
Лучший ответ

У многих проектов есть одна и та же проблема, о которой вы только что описали. Насколько я знаю, это не то, что вы, как издатель, можете контролировать. Вы можете установить политику издателя, которая позволяет автоматически указывать, что определенная версия вашей сборки должна использоваться, когда ссылки на более старые версии ваших сборок, но нет способа указать это для сборок, которые вы не контролируете (например, log4net).

С вашей стороны администратор может указать эти запросы для более старой версии log4net (которую может ссылаться ваша сборка), перенаправляя ее в определенную версию с помощью перенаправить сборку.

  • 0
    Я знаю, что ваш ответ правильный, но я стараюсь избегать этой проблемы (пусть мои клиенты редактируют файлы манифеста)
2

Вы можете обработать событие AssemblyResolve:

AppDomain current = AppDomain.CurrentDomain;
current.AssemblyResolve += current_AssemblyResolve;

Затем вы можете использовать манипуляции с строкой в ​​свойстве Name (из ResolveEventArgs), чтобы удалить номер версии и загрузить сборку без указания ее версии.

0

Стоит отметить, что из-за изменения publicKeyToken между версиями 1.2.10.0 и 1.2.11.0 log4net эта привязкаRedirect почти невозможна между этими двумя версиями по обсуждаемым причинам здесь и здесь.

Если вы используете NuGet, это еще больше проблема, потому что это означает, что вам нужно обойти NuGet, чтобы использовать версию log4net oldkey, загружаемую из здесь.

Однако я обнаружил, что даже это не удается со следующим исключением по причинам, упомянутым в вышеупомянутой ссылке:

Метод не найден: 'Void log4net.Config.BasicConfigurator.Configure()'

0

Для приложения CAD/CAM мне пришлось столкнуться с этой проблемой с некоторыми библиотеками поддержки для сторонней машины, которую мы должны были поддерживать. Что я сделал, я создал две сборки, одну связанную с одной версией, и другую, связанную с другой версией. Я поместил их обоих за один и тот же интерфейс.

Затем в нашем диалоговом окне настройки вы можете указать, какую версию использовать. Конечно, если используется некорректная версия, произойдет ошибка.

Трюк создает интерфейс, так что обе сборки могут работать без проблем. Возможно, не удастся обернуть сложный API, такой как Microsoft Office. В этом случае вам нужно отменить свое использование API и посмотреть, где используется минимальное количество вызовов, и построить интерфейс в этой точке.

В моем случае дело пришло, когда мне пришлось сбрасывать лист материала на машину. Таким образом, я создал интерфейс, в котором была обычная программа диалога установки для этой машины и процедура, которая использовала мой объект листа. Все было в этом классе.

В вашем случае вам нужно посмотреть, что вы используете в Log4net, и посмотреть, можете ли вы создать интерфейс вокруг этого.

Одно из преимуществ этого заключается в том, что вы больше не свариваете Log4Net. Правильно спроектируйте интерфейс, затем вы можете переопределить использование другого пакета. Кроме того, создание интерфейса точно определит, как ваше приложение взаимодействует с Log4net. Наконец, если Log4Net когда-либо реализует взломанное изменение, у вас есть путь к его решению.

0

Чередование другого ответа. Хакки, и могут быть осложнения, но:

Создайте код log4net в вашей DLL.
Поскольку он является открытым исходным кодом и под разумно разрешительная лицензия, вы можете редактировать файлы (отмечая, что вы это сделали), чтобы изменить видимость (и, возможно, пространства имен), чтобы он был полезен для вашего кода и не мешал потребителям.

Возможно, вы захотите добавить какой-либо код, чтобы попытаться настроить вашу библиотеку из того же места, что и остальная часть приложения, в качестве альтернативы (и гораздо более удобной), позволяющей настроить ведение журнала ваших библиотек из полностью отдельной секции файла/конфигурации.

  • 0
    Я не могу, потому что тогда мой appender выставит неправильный интерфейс (то же имя, но из другой сборки, следовательно, другого типа)
  • 0
    Ах, хорошо - вы не просто используете log4net, вы расширяете его. Вы можете сделать это ясно в вопросе
0

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

Если вы должны зависеть от библиотеки, которая может быть установлена ​​в GAC, тогда вы можете положиться на нее и иметь сразу несколько версий библиотеки, но это вряд ли будет хорошо работать с log4net (учитывая общую конфигурацию обычно используемая модель состояния) и значительно усложняет использование вашей библиотеки.

Можно отметить, что многие библиотеки не должны выводить какой-либо журнал, поскольку они не смогут достаточно хорошо предвидеть требования своих пользователей. Конфигурация log4net runtime уменьшает это до некоторой степени, хотя. Будет ли ваш код лучше, если он перейдет к использованию Tracing api, встроенного в структуру? Полученный код становится намного более легким с точки зрения зависимостей и все же позволяет компилировать некоторые сложные настройки.

0

Простым и глупым решением будет использование прокси-библиотеки, написанной на vb.net.

У меня возникла аналогичная проблема при попытке создать инструмент для MS OFFICE.

С VB я не беспокоился о том, какая версия офиса установлена.

0

Вы можете использовать контейнер IoC (например, Castle, Spring.net и т.д.), который на самом деле создает нужные вам классы, в соответствии с используемыми вами интерфейсами, как определено в файле конфигурации (или фрагменте кода).
Таким образом, вы работаете только с интерфейсами, а фактическое связывание с конкретными классами выполняется контейнером (каркасом). Это (особенно) возможно, если вы работаете с инъекцией зависимостей (см. Также Статья Фаулера об этом).
Вы получаете "позднюю привязку" к вашему коду, если используемые вами интерфейсы остаются прежними.

  • 0
    Это на самом деле не работает, независимо от того, что я делаю, у меня есть зависимость типа от базового класса / интерфейсов log4net, которым я должен соответствовать. Чтобы IoC работал, log4net должен был разделить типы на разные, инвариантные dll, хранящиеся в версии 1.0, на которые я мог ссылаться.
  • 0
    Так что пишите свои собственные интерфейсы для регистрации. Они могут иметь те же подписи, что и в log4net (таким образом, ваш код почти не меняется). Тогда вы можете использовать контейнер IoC. Взгляните и на этот: tinyurl.com/l7xmd2
Показать ещё 1 комментарий
0

EDIT: Ниже приведенное ниже предложение не работает: конкретная версия применяется во время компиляции, а не времени выполнения

Выберите ссылку на Log4Net в Visual Studio (при условии, что вы используете Visual Studio!) и покажите свойства. Установите "Специфическая версия" на "false", и я думаю, что с вами все в порядке. Вы уже пробовали это и столкнулись с проблемами?

  • 0
    После 9 лет работы с .Net я впервые слышу, что такая возможность существует . Я попробую.
  • 0
    Я бы очень хотел знать, сработает ли это для вас. Если я правильно помню, Fluent NHibernate (или это был сам NHibernate) отбросил их зависимость от log4net из-за проблемы, описанной в OP.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню