2016-10-10 10 views
3

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

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

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

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

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

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

+1

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

+0

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

+0

@Liam Да. DLL COM-взаимодействия с использованием стандартной сборки Newtonsoft.Json. –

ответ

1

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

В вашей библиотеке C#, видимой на COM, мы можем сообщить среде выполнения .NET для поиска Json DLL в каталоге библиотеки 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, ваше «перенаправление» также влияет на другую библиотеку.

+0

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

+0

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

1

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

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

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

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

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

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

0

Скопируйте файл (yourfilename.dll.config) в папке отладки для VB6 (не папка проекта) исполняемая папка и переименовать его в VB6.exe.config.

Закрыть проект VB6 и открыть его снова.