动态加载DLL
我有一个程序需要使用大量插件。
每个插件必须支持一个非常基本的接口,这个接口是在 DLL 中定义的(为了简单起见,使用 IBaseComponent)。
每个插件都将位于特定目录中(AppDirectory\plugin\plugin-type)。 每个插件可以为插件的 dll 指定任何名称 (AppDirectory\plugin\plugin-type\plugin-name.dll)。
因此,我需要检查每个插件子目录,找到每个具有支持 IBaseComponent 接口的类的插件,实例化该类并调用插件上的一些函数。
好吧,一切都很好,这一切都不是特别难。但问题是我似乎遇到了一些奇怪的问题。
每个插件都需要在单独的插件文件夹中拥有 Base.dll 文件(而不仅仅是在将加载插件的程序中),而且似乎我在动态加载具有 dll 的 dll 时收到许多错误和警告需要加载。
我正在使用:
pluginModule = System.Reflection.Assembly.ReflectionOnlyLoadFrom(PathToAssembly);
为了获取插件 dll 并使用:
types = moduleAssembly.GetTypes();
为了获取 dll 中包含的类型。 我正在迭代类型并检查单个类型是否属于 IBaseComponent 接口(表示这是一个有效的加载类):
if (type.GetInterface("FrameworkNameSpace.IBaseComponent") != null)
//it's of the IBaseComponent interface
稍后,为了从我使用的 dll 中实际创建该类的实例:
pluginModule = System.Reflection.Assembly.LoadFrom(PathToAssembly);
然后使用:
types = component.GetTypes();
为了获取模块内的类型,然后选择并加载支持与上面相同的接口的类。
问题似乎出现了
types = component.GetTypes();
当我使用:当实际尝试加载类时,而不是简单地查看它时, 。 (因此我对 LoadFrom 和 ReflectionOnlyLoad 的不同用法)
我在 GetTypes 调用上收到的异常(在第二个插件上,但从来没有在第一个插件上!)是
{"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."}
:属性为:
{"The specified module could not be found. (Exception from HRESULT: 0x8007007E)":null}
我不确定为什么会发生这种情况。该DLL位于插件文件夹中,包含IBaseComponent接口的DLL也位于每个插件目录中。我是否以错误的方式处理这个问题?
另外,我是否需要在每个插件子目录以及程序本身使用的子目录中保留包含 IBaseComponent 的 DLL 的副本,或者我是否做了不正确的操作,从而允许我删除此要求?
我知道我想使用 MEF,但不幸的是,因为我需要在 .net 2.0 上支持它,所以我无法使用 MEF。
I have a program which needs to use a large number of plugins.
Each plugin must support a very basic interface, this interface is defined in a DLL (IBaseComponent for simplicity of question sake).
Each plugin will be in a specific directory (AppDirectory\plugin\plugin-type).
Each plugin can have any name for the plugin's dll (AppDirectory\plugin\plugin-type\plugin-name.dll).
So I need to check through each plugin subdirectory, find each plugin that has a class which supports the IBaseComponent interface, instantiate the class and call some functions on the plug in.
ok, all fine and dandy, none of this is particularly hard. The problem though is that I seem to be running into some weird issues.
Every plugin needs to have the Base.dll file in the individual plugin folders (instead of just in the program that will be loading the plugin) and also it seems that I get many errors and warnings around dynamically loading a dll which have dll's that also need to be loaded.
I'm using:
pluginModule = System.Reflection.Assembly.ReflectionOnlyLoadFrom(PathToAssembly);
in order to grab the plugin dll and using:
types = moduleAssembly.GetTypes();
in order to grab the types contained within the dll.
I am iterating over the types and checking if the individual type is of the IBaseComponent interface (signifying this is a valid to load class) with:
if (type.GetInterface("FrameworkNameSpace.IBaseComponent") != null)
//it's of the IBaseComponent interface
Later, in order to actually create an instance of the class from the dll I use:
pluginModule = System.Reflection.Assembly.LoadFrom(PathToAssembly);
and then use:
types = component.GetTypes();
In order to get the types within the module then select and load the class which supports the interface same as above.
The problem seems to be on when I use:
types = component.GetTypes();
When actually trying to load the class, Instead of simply looking at it. (Hence my different usage of LoadFrom and ReflectionOnlyLoad)
The Exception I receive on the GetTypes call (on a second plug in, but never the first!) is:
{"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."}
With the LoaderExceptions property as:
{"The specified module could not be found. (Exception from HRESULT: 0x8007007E)":null}
I'm unsure why this occurs. The DLL is in the plugin folder, and the DLL containing the IBaseComponent interface is also in every one of the plugin directories. Am I going about this the wrong way?
Also is it required for me to keep a copy of the DLL containing IBaseComponent within each plugin subdirectory as well as the one used by the program itself, or am I doing something incorrectly that would allow me to remove this requirement?
I am aware of MEF which is what I wanted to use but unfortunately because I am required to support this on .net 2.0 I am unable to use MEF.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是 LoadLibrary() 失败。在我看来,你的插件依赖于一些非托管 DLL。是的,Windows 将很难找到这些 DLL,它没有理由查找插件目录。也许它第一次起作用是因为您的应用程序的默认目录恰好设置为正确的目录。这也是解决方法,使用Environment.CurrentDirectory。
准确找出哪些依赖项无法找到是关键。非托管的不会出现在 fuslogvw.exe 中,您可以从 SysInternals 的 ProcMon 实用程序的跟踪中挖掘它。
This is a LoadLibrary() failure. Sounds to me that you plugins have a dependency on some unmanaged DLLs. Yes, Windows is going to have a hard time finding these DLLs, it has no reason to look in the plugin directories. Maybe it works the first time because your app's default directory happens to be set to the correct directory. Which would then also be the workaround, use Environment.CurrentDirectory.
Finding out exactly which dependencies can not be found is key. Unmanaged ones are not going to show up in fuslogvw.exe, you can dig it out of a trace from SysInternals' ProcMon utility.