Сборка COM-взаимодействия не находит встроенную (.Net) зависимость при вызове из Vb

#c# #json.net #dependency-management #com-interop

#c# #json.net #управление зависимостями #com-interop

Вопрос:

У меня есть сборка C # COM-Interop, которую я вызываю из приложения Visual Basic 6. Эта сборка выполняет HTTP-запросы для отправки и получения JSON.

Сборка отлично работает при тестировании с помощью тестового клиента C #.

Однако при использовании ее из приложения VB6 возвращается следующая ошибка:

«Не удалось загрузить файл или сборку ‘Newtonsoft.Json, Version = 4.5.0.0, Culture = нейтральный, PublicKeyToken = 30ad4fe6b2a6aeed’ или одна из его зависимостей. Система не может найти указанный файл «.

Newtonsoft.Json.dll Находится в той же папке, что и библиотека DLL COM-Interop (TLB).

Newtonsoft.Json.dll Нужно ли загружать явно? Или, может быть, помещена в GAC?

Комментарии:

1. Так что это не Json. Сеть, которую вы зарегистрировали в COM, но другая . Сетевая сборка, использующая Json.Net ?

2. Эта ошибка возникает из вашей сборки взаимодействия C #? Возможно, вам захочется использовать что-то вроде Process Monitor, чтобы точно отслеживать, куда смотрит ваше приложение, когда оно пытается найти Newtonsoft.Json.dll досье.

3. @Liam Да. библиотека DLL COM interop использует стандартный Newtonsoft. Сборка Json.

4. Я думаю, вам нужно будет поместить библиотеку dll Newtonsoft в тот же каталог, что и COM dll. Это зависимость, поэтому необходимо иметь к ней доступ. Тем не менее, мой COM довольно ржавый

5. @Liam Любые библиотеки DLL, требуемые COM DLL, автоматически копируются туда VS2012 при сборке проекта. Итак, да, они находятся в той же папке, что и COM DLL.

Ответ №1:

Ганс предоставил отличное объяснение, почему это происходит. Позвольте мне предложить обходной путь для выполнения этой работы без необходимости регистрировать DLL Json в GAC или копировать ее в каталог VB6 EXE.

В вашей COM-видимой библиотеке C # мы можем указать .СЕТЕВАЯ среда выполнения для поиска библиотеки DLL Json в каталоге библиотеки C # вместо «обычных» путей. Мы делаем это, прикрепляя наш собственный обработчик к AssemblyResolve событию:

 AppDomain.CurrentDomain.AssemblyResolve  = (sender, e) =>
{
    // We only want this workaround for one particular DLL
    if (e.Name != "Newtonsoft.Json")
        return null;

    var myLibraryFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    var path = Path.Combine(myLibraryFolder, "Newtonsoft.Json.dll");

    return Assembly.LoadFrom(path);
};
  

Примечания об этом обходном пути:

  • Этот код работает, только если он выполняется в вашей библиотеке C # перед выполнением чего-либо, что может вызвать дрожание при загрузке библиотеки JSON. Например, ни ваша библиотека, ни любая другая библиотека .NET в вашем процессе VB6 не должны вызывать какие-либо методы, ссылающиеся на типы из библиотеки JSON, перед выполнением этого кода.

  • Вы изменяете поведение всего процесса, а не только вашей библиотеки. Если ваш процесс VB6 использует другую библиотеку с использованием JSON, ваше «перенаправление» также влияет на другую библиотеку.

Комментарии:

1. Я довольно намеренно опустил это, важно указать на подводные камни. Во-первых, возникает проблема с курицей и яйцом, DLL может потребоваться дрожанию, прежде чем ваш код начнет выполняться. И что еще хуже, это вызывает еще больший ад DLL, теперь ваш код отвечает за взлом другого COM-сервера, который также использует библиотеку. И он перестает работать, когда кто-то другой делает это также.

2. @HansPassant: Ну, иногда это обходное решение является меньшим из двух зол. Мы используем ее для проектов на основе Office на основе VBA, где предлагаемые вами решения (установка GAC или добавление DLL в каталог EXE) потребовали бы административных разрешений, которые не являются вариантом. В любом случае, я бы предпочел опубликовать обходной путь здесь, где я могу прикрепить предупреждения и обеспечить чистый и минимально навязчивый код, вместо того, чтобы заставлять читателя продолжать поиск и копировать и вставлять какое-то плохо написанное решение из какого-либо потока MSDN.

3. Этот метод отлично работает, спасибо за его предоставление. Я не хотел хранить другую сборку в GAC.

Ответ №2:

Это стандартная проблема DLL Hell, она вызвана использованием параметра /codepage для Regasm.exe . Или, чаще, Проект> Свойства> Вкладка «Сборка»> флажок «Зарегистрироваться для COM-взаимодействия». Оба делают одно и то же, они записывают путь к DLL в реестр. Это очень хороший вариант для использования, когда вы заняты разработкой и тестированием проекта, он позволяет избежать необходимости перерегистрировать DLL в GAC каждый раз, когда вы вносите изменения.

Но чего она не делает, так это не помогает CLR находить какие-либо зависимости. Обычные правила проверки остаются в силе, он ищет файл appname.exe.config в каталоге, где хранится EXE. И сначала просматривает GAC, затем в пути к EXE для зависимостей. Конфигурация остается под контролем обычной жертвы DLL-ада, кому бы ни приходилось поддерживать EXE. Часто конечный пользователь. Таким образом, явно не просматривается каталог, в котором хранится ваша [ComVisible] DLL.

Это мягкий вид ада DLL, просто ошибка, из-за которой файл не найден. Гораздо мягче, чем неприятный вид, поиск файла с правильным именем, но неправильной версией. В общем, сильная проблема с Newtonsoft.Json.dll , в дикой природе существует около 35 разновидностей. Наличие такого количества версий и такая популярная библиотека также порождают другую неприятность, программу, использующую другой COM-сервер, который также использует DLL. Но почти неизбежно другая версия. Обычно это происходит задолго до того, как вы объявили свой проект завершенным. Один из них проиграет, шансы 50-50, что это вы. 100% шансов для конечного пользователя.

Да, GAC решает эту проблему. Каждая библиотека получает версию, которую они запрашивают. В идеале Newtonsoft решила бы эту проблему за вас с помощью установщика, который развертывает DLL в GAC. Но это не тот вид обязательств, который когда-либо хотели предоставить разработчики библиотек с открытым исходным кодом. Они хотят (и нуждаются) сделать это вашей проблемой. Microsoft делает это, но у них также есть Центр обновления Windows, чтобы гарантировать развертывание критических исправлений ошибок и безопасности. И большое количество людей работают над тем, чтобы убедиться, что любые новые версии всегда обратно совместимы с исходной версией, поэтому номер версии не должен меняться.

Обратите внимание, что вы можете воспользоваться обязательствами Microsoft. Вы также можете использовать классы DataContractJsonSerializer и JavaScriptSerializer для выполнения этой работы. Часть фреймворка, они редко ошибаются.

Между тем, имейте в виду, что это просто проблема с не найденным файлом. Вам не нужно использовать GAC на вашем компьютере разработчика, и лучше, если вы этого не сделаете, так же легко скопировать файл в нужное место, чтобы среда CLR была довольна. Это тот же каталог, что и ваша тестовая программа VB6. И, дополнительная причуда с VB6, в C:Program Files (x86) Visual Studio VB6, если вы хотите использовать отладчик VB6. Используйте GAC при развертывании.