J'essaye d'écrire du code qui me permettra de charger dynamiquement des DLLs dans mon application, selon un arrangement d'application. L'idée est que la base de données à accéder est définie dans les paramètres de l'application, puis cela charge la DLL appropriée et l'affecte à une instance d'une interface pour mon application à accéder..Net dynamiquement charger DLL
Ceci est mon code au 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)
J'ai mon interface (ICRDataLayer) et le SQLServer.dll contient une implémentation de cette interface. Je veux juste charger l'assembly et l'assigner à l'objet SQLDataSource.
Le code ci-dessus ne fonctionne tout simplement pas. Aucune exception n'est levée, même la Msgbox n'apparaît pas. Je m'attendais au moins à ce que la boîte de message apparaisse avec rien dedans, mais même cela n'arrive pas!
Existe-t-il un moyen de déterminer si l'assembly chargé implémente une interface spécifique. J'ai essayé le ci-dessous mais cela ne semble pas non plus faire quoi que ce soit!
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: Un nouveau code à partir des exemples de Vlad:
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
Ci-dessus du module dans chaque DLL, converti de l'exemple C# de Vlad.
ci-dessous est mon code pour apporter la 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: Mise en œuvre basée sur le code de Paul Kohler
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
je reçois l'erreur suivante avec ce code: Impossible de diffuser l'objet de type SQLServer.CR
DataSource.SQLServer 'pour taper' DynamicAssemblyLoading.ICRDataLayer '.
La DLL réelle est dans un projet différent appelé SQLServer dans la même solution que mon code d'implémentation. CRDataSource est un espace de noms et SQLServer est le nom de classe réel de la DLL. La classe SQLServer implémente ICRDataLayer, donc je ne comprends pas pourquoi elle ne pourrait pas la convertir. Le nom est significatif ici, je n'aurais pas pensé que ce serait.
Code de travail final
Contenu de 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 pour charger la 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
Ne pas utiliser 'ty.Name.Contains ("ICRDataLayer")' - vérifier qu'il "implémente le type" avec 'assemblyType.GetInterface ("votre espace de noms etc.ICRDataLayer") '(voirhttp: //msdn.microsoft.com/en-us/library/tcctb9t8.aspx) il vous donnera' Nothing' s'il n'est pas implémenté par le type en cours.En outre, l'exception semble indiquer que l'interface n'est pas implémentée, utilisez-vous une DLL partagée pour cela - elle doit être la même. PK –
Vérifiez à nouveau la solution ci-dessous ... –
Cela fonctionne! J'ai fini par utiliser votre code Paul, il fonctionne exactement comme j'en ai besoin. Pour tous ceux qui pourraient rencontrer ce fil dans le futur, j'ajouterai mon code final dans le post original, donc j'espère qu'ils auront plus de facilité à le faire fonctionner que moi. Merci à tous pour votre aide – hermiod