.Net Dynamisch DLL Laden
Ich versuche, code zu schreiben, dass wird mir erlauben, das dynamische laden von DLLs in meiner Anwendung, je nach Anwendung einstellen. Die Idee ist, dass die Datenbank auf die zugegriffen wird, in den Programmeinstellungen und dann dieser lädt die entsprechende DLL, und ordnet es zu einer Instanz einer Schnittstelle für meine Anwendung zugreifen.
Dies ist mein code im moment:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim obj As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj, ICRDataLayer)
MsgBox(SQLDataSource.ModuleName & vbNewLine & SQLDataSource.ModuleDescription)
Habe ich mein interface (ICRDataLayer) und die SQLServer.dll enthält eine Implementierung dieser Schnittstelle. Ich will einfach nur, um die assembly zu laden und weisen Sie es dem SQLDataSource-Objekt.
Der obige code funktioniert einfach nicht. Es gibt auch keine exceptions geworfen, auch die Msgbox nicht angezeigt.
Ich hätte erwartet, dass zumindest die messagebox erscheinen mit nichts drin, aber auch das ist nicht passiert!
Gibt es eine Möglichkeit zu bestimmen, ob die geladene assembly implementiert eine bestimmte Schnittstelle. Ich habe versucht, das unten, aber das scheint auch nicht, etwas zu tun!
For Each loadedType As Type In ass.GetTypes
If GetType(ICRDataLayer).IsAssignableFrom(loadedType) Then
Dim obj1 As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString, True)
SQLDataSource = DirectCast(obj1, ICRDataLayer)
End If
Next
EDIT: Neuer code von Vlad Beispiele:
Module CRDataLayerFactory
Sub New()
End Sub
' class name is a contract,
' should be the same for all plugins
Private Function Create() As ICRDataLayer
Return New SQLServer()
End Function
End Module
Oben ist das Modul in jeder DLL, Umgerechnet aus Vlad ' s C# Beispiel.
Unten ist mein code zu verwenden, um die in der DLL:
Dim SQLDataSource As ICRDataLayer
Dim ass As Assembly = Assembly. _
LoadFrom("M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\SQLServer.dll")
Dim factory As Object = ass.CreateInstance("CRDataLayerFactory", True)
Dim t As Type = factory.GetType
Dim method As MethodInfo = t.GetMethod("Create")
Dim obj As Object = method.Invoke(factory, Nothing)
SQLDataSource = DirectCast(obj, ICRDataLayer)
EDIT: Implementierung, basierend auf Paul Kohler-code
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
For Each ty As System.Type In s
If ty.Name.Contains("ICRDataLayer") Then
MsgBox(ty.Name)
plugin = DirectCast(Activator.CreateInstance(assemblyType), ICRDataLayer)
MessageBox.Show(plugin.ModuleName)
End If
Next
Bekomme ich die folgende Fehlermeldung mit diesem code:
Unable to cast object of type 'SQLServer.CRDataSource.SQLServer' to type 'DynamicAssemblyLoading.ICRDataLayer'.
Die DLL in einem anderen Projekt namens SQLServer in die gleiche Lösung wie meine Implementierung code. CRDataSource ist ein namespace und SQLServer ist die eigentliche Klasse name der DLL.
Der SQLServer-Klasse implementiert ICRDataLayer, so verstehe ich nicht, warum es nicht in der Lage sein, um Sie zu wirken.
Ist die Namensgebung hier von Bedeutung wäre, wäre ich nicht dachte, es wäre.
Endgültige code
Inhalt PluginUtility:
enter code here Public Shared Function GetInstances1(Of Type)(ByVal baseDir As String, ByVal searchPattern As String) As System.Type()
Dim tmpInstances As New List(Of Type)
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetTypes
Dim s As System.Type() = assemblyType.GetInterfaces
Return s.ToArray()
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
End Try
End Function
Code zum laden der DLL:
enter code here
Dim basedir As String = "M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer\bin\Debug\"
Dim searchPattern As String = "*SQL*.dll"
Dim plugin As CRDataLayer.ICRDataLayer
Try
Dim file As String
For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
For Each assemblyType In Assembly.LoadFrom(file).GetExportedTypes
If assemblyType.GetInterface("CRDataLayer.ICRDataLayer") IsNot Nothing Then
plugin = DirectCast(Activator.CreateInstance(assemblyType), CRDataLayer.ICRDataLayer)
MessageBox.Show(plugin.ModuleDescription)
End If
Next
Next
Catch exp As TargetInvocationException
If (Not exp.InnerException Is Nothing) Then
Throw exp.InnerException
End If
Catch ex As Exception
MsgBox(ex.Message)
Clipboard.SetText(ex.Message)
End Try
- Verwenden Sie nicht
ty.Name.Contains("ICRDataLayer")
- überprüfen, dass es "implementiert den Typ" mitassemblyType.GetInterface("your namespace etc.ICRDataLayer")
(siehe http://msdn.microsoft.com/en-us/library/tcctb9t8.aspx) es wird IhnenNothing
wenn Ihr nicht implementiert, indem der aktuelle Typ. Auch, die Ausnahme scheint, um anzuzeigen, dass die Schnittstelle nicht implementiert, verwenden Sie eine gemeinsame DLL für diese - es muss der gleiche. PK - Überprüfen Sie die Lösung unten wieder...
- Es funktioniert! Ich landete mit Ihrem code Paul, es funktioniert genau so, wie ich es brauche. Für alle, die kommen können, über diesen thread in der Zukunft, ich will hinzufügen, meine Letzte code in der original-Beitrag, so hoffentlich können Sie haben eine einfachere Zeit bekommen, diese arbeiten als ich. Danke allen für Ihre Hilfe
Du musst angemeldet sein, um einen Kommentar abzugeben.
Version 2 - Dieses Beispiel lädt eine DLL aus dem es das aktuelle Verzeichnis.
Es gibt 2 Projekte, 1-Konsolenanwendung Projekt, und ein "Modul" - Projekt (das Modul 'coppies" seine DLL in das Arbeitsverzeichnis der Konsole app).
Im folgenden Beispiel wird einfach veranschaulicht, das dynamische laden einer DLL, die eine Schnittstelle implementiert. Die
IModule
Schnittstelle nur berichtet seinen Namen.PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll")
erstellen eine Instanz von jedemIModule
Instanz gefunden, die in einer DLL im aktuellen Verzeichnis mit der Endung ".Module.dll". Es ist eine reflektierte VB.NET version direkt aus der Mini-SQL-Abfrage.Mit, dass im Hinterkopf so etwas wie:
Sollte erfüllen Ihre Anforderung. Dann brauchen Sie nur zu wählen, welchen man ausführen!
Code:
In "VB.LoaderDemo Colsole App"
In "Sample1 DLL" (Referenzen 'VB.LoaderDemo' für IModule)
Ausgabe:
Ist der Typ
ICRDataLayer
in der DLL definiert sind, Sie gehen zu laden? Wenn dem so ist, scheinen Sie bereits Verweis auf die DLL in Ihr Projekt-Einstellungen.Müssen Sie nur Reflexion:
Edit: Wenn
ICRDataLayer
ist in der Applikation umgesetzt, und das plugin nur die Schnittstelle implementiert, müssen Sie das plugin, um eine Fabrik für Sie: (sorry für C# - code, ich bin nicht vertraut mit VB.NET's syntax)Code der Anwendung sollte wie folgt Aussehen:
CreateInstance
? Was wird in derobj
Ein paar Dinge zu suchen in Ihrem code
die Montage ist korrekt geladen, im Fall
es scheitert an Abhängigkeiten zu prüfen