.Net动态加载DLL [英] .Net Dynamically Load DLL

查看:223
本文介绍了.Net动态加载DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一些代码,这将允许我根据应用程序设置将DLL动态加载到我的应用程序中。想法是在应用程序设置中设置要访问的数据库,然后加载相应的DLL并将其分配给我的应用程序访问的接口实例。



这是我现在的代码:

  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)

我有我的界面(ICRDataLayer),SQLServer.dll包含这个界面的一个实现。我只想加载程序集并将其分配给SQLDataSource对象。



上面的代码不起作用。没有异常抛出,即使Msgbox不出现。
我至少会发现消息框中没有显示任何内容,但即使这样也不会发生!



有没有办法确定装载组件实现了一个特定的接口我试过下面,但这似乎也没有做任何事情!

 对于每个loadedType作为类型在ass.GetTypes 
如果GetType(ICRDataLayer).IsAssignableFrom(loadedType)然后
Dim obj1 As Object = ass.CreateInstance(GetType(ICRDataLayer).ToString,True)
SQLDataSource = DirectCast(obj1,ICRDataLayer)
结束如果
下一个






编辑:Vlad的例子的新代码

 模块CRDataLayerFactory 
Sub New()
End Sub
'类名是一个合同,
'应该是相同的所有插件
私有函数Create()作为ICRDataLayer
返回新的SQLServer()
结束功能
结束模块

以上是每个DLL中的模块,从Vlad的C#示例中转换。



以下是我的代码来引入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方法As MethodInfo = t.GetMethod(Create)
Dim obj As Object = method.Invoke工厂,没有)
SQLDataSource = DirectCast(obj,ICRDataLayer)






编辑:基于保罗·科勒的代码执行

  Dim file As String 
对于每个文件在Directory.GetFiles(baseDir,searchPattern,SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
对于每个assemblyType在Assembly.LoadFrom(文件).GetTypes

Dim s As System.Type()= assemblyType.GetInterfaces
对于每个ty As System.Type在s

如果ty.N ame.Contains(ICRDataLayer)然后
MsgBox(ty.Name)
plugin = DirectCast(Activator.CreateInstance(assemblyType),ICRDataLayer)
MessageBox.Show(plugin.ModuleName)
结束如果
下一个

我收到以下错误代码:



无法将类型为SQLServer.CRDataSource.SQLServer的对象转换为键入DynamicAssemblyLoading.ICRDataLayer。



实际DLL在与我的实现代码相同的解决方案中与另外一个名为SQLServer的项目。 CRDataSource是一个命名空间,SQLServer是DLL的实际类名。
SQLServer类实现ICRDataLayer,所以我不明白为什么它不能转换它。
这里的命名很重要,我不会以为会是这样的。






工作代码



PluginUtility的内容:

  enter公共共享函数GetInstances1(Of Type)(ByVal baseDir As String,ByVal searchPattern As String)As System.Type()
Dim tmpInstances As New List(Of Type)
尝试
Dim文件As String
对于Directory.GetFiles(baseDir,searchPattern,SearchOption.TopDirectoryOnly)中的每个文件
Dim assemblyType As System.Type
对于Assembly.LoadFrom(file).GetTypes

Dim s As System.Type()= assemblyType.GetInterfaces
返回s.ToArray()

下一个
下一个
Catch exp As TargetInvocationException
如果(不是exp.InnerException Is Nothing)然后
抛出exp.InnerException
结束如果
结束尝试
结束函数

加载DLL的代码: / p>

 在此输入代码
Dim basedir As String =M:\MyProgs\WebService\DynamicAssemblyLoading\SQLServer \bin\Debug\
Dim searchPattern As String =* SQL * .dll
Dim plugin As CRDataLayer.ICRDataLayer

尝试
Dim文件作为String
对于每个文件在Directory.GetFiles(baseDir,searchPattern,SearchOption.TopDirectoryOnly)
Dim assemblyType As System.Type
对于每个assemblyType在Assembly.LoadFrom(文件).GetExportedTypes

如果assemblyType.GetInterface(CRDataLayer.ICRDataLayer)IsNot Nothing然后
plugin = DirectCast(Activator.CreateInstance(assemblyType),CRDataLayer.ICRDataLayer)
MessageBox.Show(plugin.ModuleDescription )
结束如果

Nex t
下一个
Catch exp As TargetInvocationException
如果(不是exp.InnerException is Nothing)然后
抛出exp.InnerException
结束如果
捕获ex As Exception
MsgBox(ex.Message)
Clipboard.SetText(ex.Message)
结束尝试


解决方案

版本2 - 此示例从当前目录加载一个DLL。
有2个项目,1个控制台应用程序项目和一个模块项目(模块'coppies'的DLL到控制台应用程序的工作目录)。



下面的示例简单地演示了动态加载实现接口的DLL。 IModule 界面刚刚报告其名称。 PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory,* .Module.dll)将创建任何 IModule 在当前目录中以.Module.dll结尾的DLL中找到的实例。这是一个反映的VB.NET版本直接从Mini SQL查询。



考虑到这一点:

  Dim modules As IModule()= PlugInUtility.GetInstances(Of ICRDataLayer)(Environment.CurrentDirectory,* .Server.dll)
pre>

应满足您的要求。那么你只需要选择执行哪一个!



代码:



在VB.LoaderDemo Colsole App中

 'IModule。 vb 
公共接口IModule
属性ModuleName()As String
结束接口

'PlugInUtility.vb
导入System.IO
导入系统.Reflection
公共类PlugInUtility
公共共享函数GetInstances(Of T)(ByVal baseDir As String,ByVal searchPattern As String)As T()
Dim tmpInstances As New List(Of T)
尝试
Dim file As String
对于Directory.GetFiles(baseDir,searchPattern,SearchOption.TopDirectoryOnly)中的每个文件
Dim assemblyType作为类型
对于每个assemblyType在程序集中。 LoadFrom(file).GetTypes()
If(not assemblyType.GetInterface(GetType(T).FullName)Is Nothing)Then
tmpI nstances.Add(DirectCast(Activator.CreateInstance(assemblyType),T))
End If
Next
下一个
Catch exp As TargetInvocationException
如果(不是exp.InnerException是没有)然后
抛出exp.InnerException
结束如果
结束尝试
返回tmpInstances.ToArray()
结束函数
结束类

'MainModule.vb
模块MainModule
Sub Main()
Dim plugins As IModule()= PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory,* .Module。 dll)
Dim m As IModule
对于每个m在插件
Console.WriteLine(m.ModuleName)
下一个
End Sub
结束模块

在Sample1 DLL(引用IModule的VB.LoaderDemo

 导入VB.LoaderDemo 

公共类MyModule1
I补充IModule

Dim _name As String

Public Sub New()
_name =Sample 1,Module 1
End Sub

公共属性ModuleName()As String实现IModule.ModuleName
获取
返回_name
结束获取
设置(ByVal值As String)
_name = value
结束集
结束属性

结束类

输出是:

 >样本1,模块1 


I am trying to write some code that will allow me to dynamically load DLLs into my application, depending on an application setting. The idea is that the database to be accessed is set in the application settings and then this loads the appropriate DLL and assigns it to an instance of an interface for my application to access.

This is my code at the 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)

I have my interface (ICRDataLayer) and the SQLServer.dll contains an implementation of this interface. I just want to load the assembly and assign it to the SQLDataSource object.

The above code just doesn't work. There are no exceptions thrown, even the Msgbox doesn't appear. I would've expected at least the messagebox appearing with nothing in it, but even this doesn't happen!

Is there a way to determine if the loaded assembly implements a specific interface. I tried the below but this also doesn't seem to do anything!

        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: New code from Vlad's examples:

    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

Above is Module in each DLL, converted from Vlad's C# example.

Below is my code to bring in the 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: Implementation based on Paul Kohler's 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

I get the following error with this code:

Unable to cast object of type 'SQLServer.CRDataSource.SQLServer' to type 'DynamicAssemblyLoading.ICRDataLayer'.

The actual DLL is in a different project called SQLServer in the same solution as my implementation code. CRDataSource is a namespace and SQLServer is the actual class name of the DLL. The SQLServer class implements ICRDataLayer, so I don't understand why it wouldn't be able to cast it. Is the naming significant here, I wouldn't have thought it would be.


Final Working code

Contents of 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 to load the 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

解决方案

Version 2 - This sample loads up a DLL from it current directory. There are 2 projects, 1 console application project and a "module" project (the module 'coppies' its DLL to the working directory of the console app).

The sample below simply demonstrates dynamically loading a DLL that implements an interface. The IModule interface just reports its name. PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll") will create an instance of any IModule instance found in a DLL within the current directory ending with ".Module.dll". It's a reflected VB.NET version straight out of Mini SQL Query.

With that in mind something like:

Dim modules As IModule() = PlugInUtility.GetInstances(Of ICRDataLayer)(Environment.CurrentDirectory, "*.Server.dll")

Should satisfy your requirement. Then you just need to chose which one to execute!

The code:

In "VB.LoaderDemo Colsole App"

' IModule.vb
Public Interface IModule
    Property ModuleName() As String
End Interface

' PlugInUtility.vb
Imports System.IO
Imports System.Reflection
Public Class PlugInUtility
    Public Shared Function GetInstances(Of T)(ByVal baseDir As String, ByVal searchPattern As String) As T()
        Dim tmpInstances As New List(Of T)
        Try
            Dim file As String
            For Each file In Directory.GetFiles(baseDir, searchPattern, SearchOption.TopDirectoryOnly)
                Dim assemblyType As Type
                For Each assemblyType In Assembly.LoadFrom(file).GetTypes()
                    If (Not assemblyType.GetInterface(GetType(T).FullName) Is Nothing) Then
                        tmpInstances.Add(DirectCast(Activator.CreateInstance(assemblyType), T))
                    End If
                Next
            Next
        Catch exp As TargetInvocationException
            If (Not exp.InnerException Is Nothing) Then
                Throw exp.InnerException
            End If
        End Try
        Return tmpInstances.ToArray()
    End Function
End Class

' MainModule.vb
Module MainModule
    Sub Main()
        Dim plugins As IModule() = PlugInUtility.GetInstances(Of IModule)(Environment.CurrentDirectory, "*.Module.dll")
        Dim m As IModule
        For Each m In plugins
            Console.WriteLine(m.ModuleName)
        Next
    End Sub
End Module

In "Sample1 DLL" (references 'VB.LoaderDemo' for IModule)

Imports VB.LoaderDemo

Public Class MyModule1
    Implements IModule

    Dim _name As String

    Public Sub New()
        _name = "Sample 1, Module 1"
    End Sub

    Public Property ModuleName() As String Implements IModule.ModuleName
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

End Class

The output is:

> Sample 1, Module 1

这篇关于.Net动态加载DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆