2016-10-10 2 views
3

Ich habe eine C# COM-Interop-Assembly, die ich aus einer Visual Basic 6-Anwendung aufrufen. Diese Assembly führt HTTP-Anforderungen zum Senden und Abrufen von JSON aus.COM-Interop-Assembly findet keine systemeigene (.Net) Abhängigkeit, wenn von Vb aufgerufen

Die Baugruppe funktioniert einwandfrei, wenn sie mit einem C# -Testclient getestet wird.

Wenn es jedoch aus mit dem VB6 app, wird der folgende Fehler zurückgegeben:

„kann nicht Datei oder Assembly‚lädt Newtonsoft.Json, Version = 4.5.0.0, Culture = neutral, PublicKeyToken = 30ad4fe6b2a6aeed 'oder eine seiner Abhängigkeiten. Das System kann die angegebene Datei nicht finden. "

Die Newtonsoft.Json.dll befindet sich im selben Ordner wie die COM-Interop DLL (TLB).

Muss die Newtonsoft.Json.dll explizit geladen werden? Oder vielleicht in der GAC platziert?

+1

Es ist also nicht Json.Net, das Sie in COM registriert haben, aber eine andere .Net-Assembly, die Json.Net verwendet? – Liam

+0

Kommt dieser Fehler von Ihrer C# Interop-Assembly? Sie möchten etwas wie Process Monitor verwenden, um genau zu beobachten, wo Ihre Anwendung sucht, wenn es versucht, die Newtonsoft.Json.dll-Datei zu finden. –

+0

@Liam Ja. Die COM-Interop-DLL verwendet die standardmäßige Newtonsoft.Json-Assembly. –

Antwort

1

Hans lieferte eine großartige Erklärung für warum dies passiert. Lassen Sie mich eine Problemumgehung anbieten, um diese Arbeit ohne zu machen, die Json DLL in der GAC zu registrieren oder es in dem VB6 EXE-Verzeichnis zu kopieren.

In Ihrer COM-visible C# -Bibliothek können wir der .NET-Laufzeitumgebung mitteilen, dass sie anstelle der "normalen" Pfade nach der Json-DLL im Verzeichnis der C# -Bibliothek suchen soll. Wir tun das durch unsere eigenen Handler zum AssemblyResolve Ereignisse Befestigung:

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); 
}; 

Hinweise zu dieser Problemumgehung:

  • Dieser Code funktioniert nur, wenn es in C# Bibliothek ausgeführt wird, bevor etwas zu tun, das könnte Der Jitter lädt die JSON-Bibliothek. Zum Beispiel müssen weder Ihre Bibliothek noch andere .NET-Bibliotheken in Ihrem VB6-Prozess vor der Ausführung dieses Codes Methoden zur Methodenreferenzierung aus der JSON-Bibliothek aufrufen.

  • Sie ändern das Verhalten des gesamten Prozesses, nicht nur Ihre Bibliothek. Wenn Ihr VB6-Prozess eine andere Bibliothek verwendet, die JSON verwendet, wirkt sich Ihre "Weiterleitung" auch auf die andere Bibliothek aus.

+0

Ich habe dies absichtlich ausgelassen, wichtig, um auf die Fallstricke hinzuweisen. Zuerst gibt es das Henne-und-Ei-Problem, die DLL könnte vom Jitter benötigt werden * bevor * Ihr Code startet. Und noch schlimmer, es verursacht * mehr * DLL Hell, jetzt ist Ihr Code dafür verantwortlich, einen anderen COM-Server zu zerstören, der ebenfalls die Bibliothek benutzt. Und es hört auf zu arbeiten, wenn jemand anderes das auch tut. –

+0

@HansPassant: Nun, manchmal ist diese Problemumgehung das kleinere Übel. Wir verwenden es für Office-VBA-basierte Projekte, bei denen Ihre vorgeschlagenen Lösungen (GAC-Installation oder das Werfen der DLL in das Verzeichnis der EXE) administrative Berechtigungen erfordern - was keine Option ist.Wie auch immer, ich möchte lieber die Problemumgehung hier veröffentlichen, wo ich Warnungen anbringen und sauberen und minimal intrusiven Code sicherstellen kann, anstatt dass der Leser weiter sucht und einige schlecht geschriebene Lösungen aus einem MSDN-Thread kopiert und kopiert. – Heinzi

1

Dies ist ein Standard-DLL-Hell-Problem, das durch die Verwendung der Option/codepage für Regasm.exe verursacht wird. Oder häufiger das Register "Projekt> Eigenschaften> Erstellen"> "Für COM-Interop registrieren". Beide machen das gleiche, sie schreiben den Pfad zur DLL in die Registry. Es ist eine sehr gute Option zu verwenden, wenn Sie mit der Entwicklung und dem Testen des Projekts beschäftigt sind, es vermeidet, die DLL in dem GAC jedes Mal neu zu registrieren, wenn Sie eine Änderung vornehmen.

Aber was es tut nicht tun, ist die CLR helfen, Abhängigkeiten zu finden. Die normalen Prüfregeln bleiben in Kraft. Sie suchen nach einer Datei namens appname.exe.config in dem Verzeichnis, in dem die EXE gespeichert ist. Und zuerst schaut im GAC, als nächstes im EXE-Pfad nach Abhängigkeiten. Die Konfiguration bleibt unter der Kontrolle des üblichen Opfers von DLL Hell, wer die EXE behalten muss. Häufig der Endbenutzer. Also, explizit, es tut nicht in das Verzeichnis suchen, in dem Ihre [ComVisible] DLL gespeichert ist.

Es ist die milde Art von DLL Hell, nur eine einfache Datei-nicht-gefundenen Missgeschick. Viel milder als die böse Art, eine Datei mit dem richtigen Namen, aber der falschen Version zu finden. Im Allgemeinen ein starkes Problem mit Newtonsoft.Json.dll gibt es etwa 35 Versionen in freier Wildbahn. Wenn man so viele Versionen hat und es so eine populäre Bibliothek ist, erzeugt man auch die andere Art von Boshaftigkeit, wobei das Programm einen anderen COM-Server benutzt, der auch die DLL benutzt. Aber fast zwangsläufig eine andere Version. Tendiert dazu, lange nachdem Sie Ihr Projekt beendet haben. Einer von ihnen wird verlieren, 50-50 Chancen, dass Sie es sind. 100% Quoten für den Endnutzer.

Ja, die GAC löst dieses Problem. Jede Bibliothek erhält die gewünschte Version. Im Idealfall löst Newtonsoft dieses Problem mit einem Installer, der die DLL in den GAC implementiert. Aber es ist nicht die Art von Engagement, die Open-Source-Bibliotheksautoren jemals bieten möchten. Sie wollen (und müssen) es zu Ihrem Problem machen. Microsoft tut dies, aber sie haben auch Windows Update, um sicherzustellen, dass kritische Bug- und Sicherheitsfixes bereitgestellt werden. Und eine große Anzahl von Leuten arbeitet daran, sicherzustellen, dass alle neuen Versionen immer abwärtskompatibel zur ursprünglichen Version sind, so dass sich die Versionsnummer nicht ändern muss.

Beachten Sie, dass Sie können Vorteil von Microsofts Engagement nutzen. Sie können auch die Klassen DataContractJsonSerializer und JavascriptSerializer verwenden, um diese Aufgabe zu erledigen. Teil des Rahmens, sie verstehen es selten falsch.

Unterdessen beachten Sie, dass nur ein Datei-nicht-gefunden-Problem ist.Sie müssen den GAC nicht auf Ihrem Dev-Computer verwenden, und es ist besser, wenn Sie es nicht tun, ist es genauso einfach, die Datei an den richtigen Ort zu kopieren, um die CLR glücklich zu machen. Welches ist das gleiche Verzeichnis wie Ihr VB6-Testprogramm. Und, zusätzliche Eigenart mit VB6, in C: \ Programme (x86) \ Visual Studio \ VB6, wenn Sie den VB6-Debugger verwenden möchten. Verwenden Sie den GAC beim Bereitstellen.

0

Kopieren Sie die Datei (yourfilename.dll.config) in Ihrem Debug-Ordner VB6 (nicht Ihren Projektordner) ausführbare Ordner und benennen Sie sich in VB6.exe.config.

Schließen Sie Ihr Projekt VB6 und öffnen Sie es erneut.